【问题标题】:Cross referencing tables in Ruby on RailsRuby on Rails 中的交叉引用表
【发布时间】:2018-05-03 08:30:23
【问题描述】:

schema db

我有一个 ads 表,它与 ad_address 和 ad_copies 表具有 1:n 的关系。 然后是类别和子类别表,其中类别与子类别表具有 1:n 关系,子类别表与 ads 表具有 1:n 关系。

因此 subcategory 表有一个名为 id_categories 的引用字段,ads 表有一个名为 id_subcategories 的引用字段。

ads_address 和 ads_copy 表都有一个 ad_id 字段。

现在我一直忙于尝试将数据从 json 文件(以前的数据库)获取到新的 rails 应用程序中。我发现这个先前数据库的架构包含一个单独的表,其中包含所有参考字段,即 id_categories、id_subcategories 和 ad_id 字段。

create_table "rel_anuncio", primary_key: ["id_anuncio", "id_categoria", "id_subcategoria"], force: :cascade, options: "ENGINE=MyISAM DEFAULT CHARSET=utf8" do |t|
  t.integer "id_anuncio", null: false
  t.integer "id_categoria", null: false
  t.integer "id_subcategoria", null: false
  t.integer "orden", null: false
end

以下是我播种广告记录的方式(json 文件的表名是西班牙语):

if row['name'] == "categorias"

row["data"].each do |record|
  @cat = Category.create!(
    user_id: user.id,
    name: record["nombre"]
  )
end

elsif row['name'] == "subcategorias"

row["data"].each do |record|
  @subcat = Subcategory.create!(
    category_id: @cat.id,
    name: record["nombre"]
    )
end

row["data"].each do |record|
  @ad = Ad.create!(
    user_id: user.id,
    subcategory_id: @subcat.id,
    [..]
    )
end

我得到"NoMethodError: undefined method 'id' for nil:NilClass""subcategory_id: @subcat.id" 行,因为没有subcategory_id 可以链接到我意识到的广告记录,因为subcategory_id 在不同的表中。

现在我知道必须有一种方法可以在哈希中交叉引用这些 id,以便您可以查看哪些 id 号属于哪个记录。例如,如果您有 id_subcategory: 3,那么它必须属于名称为“Wok Restaurant”且 id:4 的广告记录。

我想在我的 rails 应用程序中为我的广告记录播种正确的类别和子类别。

更一般地说,我想知道有人会如何处理导入数据库的 json 文件,该数据库的架构与您自己在 railsapp 中的数据库不同。

这是 json 文件的示例(仅每个表的第一行):

[
  {"type":"header","version":"4.7.9","comment":"Export to JSON plugin for PHPMyAdmin"},
  {"type":"database","name":"qqx486"},
  {"type":"table","name":"anuncios","database":"qqx486","data":
    [
      {"id":"1","empresa":"Wok Bufet Gran Oriente","tel":"971 315 964","fax_principal":"","movil_principal":"","email_principal":"","web":"","facebook":"","horario_v_principal":"","horario_i_principal":"Abierto mediod\u00eda y noche","direccion_principal":"C\/ Jos\u00e9 Zornoza Bernabeu, 15, L2","poblacion_principal":"EIVISSA","activo":"no","tam_anuncio":"completa","twitter":"","link":"no","general":"no","isla":"ibiza","subtitulo":"","comentario":"","modificacion":"0000-00-00 00:00:00","promo1":"0","promo2":"0","instagram":"","tel2":"","tel3":"","tel4":"","movil2":"","movil3":"","movil4":""},
    ]
  }
  ,{"type":"table","name":"anuncios_direcciones","database":"qqx486","data":
    [
      {"id":"157","id_anuncio":"1","direccion":"C\/ Sant Jaume, 114","poblacion":"SANTA EUL\u00c0RIA","telefono":" 971 336 274","fax":"","movil":"","email":"","horario_i":"","horario_v":""},
    ]
  }
  ,{"type":"table","name":"anuncios_gps_a","database":"qqx486","data":
    [
      {"id":"1","id_anuncio":"22","lat":"38.9082100","lon":"1.4289690","accuracy":"10"},
    ]
  }
  ,{"type":"table","name":"anuncios_gps_b","database":"qqx486","data":
    [
      {"id_anuncio_direcciones":"459","id_anuncio":"1068","lat":"0.0000000","lon":"0.0000000","acc":"0"},
    ]
  }
  ,{"type":"table","name":"anuncios_textos","database":"qqx486","data":
    [
      {"id_anuncio":"1","id_idioma":"1","descripcion":""},
    ]
  }
  ,{"type":"table","name":"caracteristicas","database":"qqx486","data":
    [
      {"id":"1","nombre":"Jard\u00edn"},
    ]
  }
  ,{"type":"table","name":"caracteristicas_textos","database":"qqx486","data":
    [
      {"id_caracteristica":"1","id_idioma":"1","titulo":"Jard\u00edn"},
    ]
  }
  ,{"type":"table","name":"categorias","database":"qqx486","data":
    [
      {"id":"1","nombre":"RESTAURANTES Y ALIMENTACI\u00d3N","color":"","activo":"si","bdd":"guias","orden":"1","promoI":"0","promoF":"0","islas":"3"},
    ]
  }
  ,{"type":"table","name":"categorias_porsi","database":"qqx486","data":
    [
      {"id":"1","nombre":"RESTAURANTES Y ALIMENTACI\u00d3N","color":"","activo":"si","bdd":"guias","orden":"1","promoI":"0","promoF":"0"},
    ]
  }
  ,{"type":"table","name":"categorias_textos","database":"qqx486","data":
    [
      {"id_categoria":"1","id_idioma":"1","titulo":"RESTAURANTES Y ALIMENTACI\u00d3N","clave":""},
    ]
  }
  ,{"type":"table","name":"enlaces","database":"qqx486","data":
    [
      {"id":"1","nombre":"Digital Grafic Ibiza","web":"http:\/\/www.bestof.org"}
    ]
  }
  ,{"type":"table","name":"enlaces_textos","database":"qqx486","data":
    [
      {"id_enlace":"1","id_idioma":"1","descripcion":"Empresa en Ibiza"},
    ]
  }
  ,{"type":"table","name":"idiomas","database":"qqx486","data":
    [
      {"id":"1","nombre":"Espa\u00f1ol","self":"es","color":"F00"},
    ]
  }
  ,{"type":"table","name":"inmuebles","database":"qqx486","data":
    [
      {"id":"1","ref":"Roca Llisa","id_inmobiliaria":"91","tipo":"piso","estado":"","zona":"Santa Eulalia","sup_vivienda":"0","sup_parcela":"0","sup_terrazas":"0","plantas":"0","dormitorios":"3","banyos":"2","piscina":"no","parking":"no","entorno":"","precio":"380000","activo":"si"},
    ]
  }
  ,{"type":"table","name":"inmuebles_textos","database":"qqx486","data":
    [
      {"id_inmueble":"1","id_idioma":"1","titulo":"Roca Llisa","descripcion":"Apartamento d\u00faplex, cocina, sal\u00f3n\/comedor, 2 terrazas, preciosas vistas al mar, piscina y paddle tenis comunitarios."},
    ]
  }
  ,{"type":"table","name":"playas","database":"qqx486","data":
    [
      {"id":"1","nombre":"PLATJA DE TALAMANCA","longitud":"900","orientacion":"SE","google":"https:\/\/www.google.es\/maps\/place\/Cala+Talamanca\/@38.9132677,1.4565971,16z\/data=!4m2!3m1!1s0x1299414743b6e207:0xe628e2f006419c0d","cnauticas":"38\u00b055\u201900.8\u201dN 1\u00b027\u201916.8\u201dE","municipio":"Eivissa","activo":"si","orden":"0"},
    ]
  }
  ,{"type":"table","name":"playas_textos","database":"qqx486","data":
    [
      {"id_playa":"1","id_idioma":"1","breve":"Playa de arena fina a pocos minutos a pie de Marina Botafoch y a 1,8 km. del centro de la ciudad de Eivissa.","descripcion":"Se trata de una bah\u00eda cerrada, poco profunda, ideal para el ba\u00f1o sin ning\u00fan peligro y muy bien protegida por los vientos. Gran variedad en restaurantes, bares y chiringuitos, incluso algunos est\u00e1n abiertos todo el a\u00f1o. Existe una pasarela de madera a lo largo de casi toda la playa. Se realizan cursos para iniciarse en deportes n\u00e1uticos como el catamar\u00e1n, kayak y windsurf.","servicios":"Restaurantes y chiringuitos \u2013 Hoteles \u2013 Alquiler de tumbonas y sombrillas \u2013 Deportes acu\u00e1ticos \u2013 Duchas y WC p\u00fablicos \u2013 Acceso minusv\u00e1lidos \u2013 Parking gratis \u2013 Transporte p\u00fablico.","llegar":"En coche, en autob\u00fas de l\u00ednea regular o en una barquita que va del puerto de Eivissa hasta Botafoch, y de ah\u00ed puede ir andando llegando en pocos minutos."},
    ]
  }
  ,{"type":"table","name":"promo","database":"qqx486","data":
    [
      {"id":"1","idioma":"1","empresa_id":"943","titulo":"10% Descuento","tituloCR":"8","tituloCG":"8","tituloCB":"8","tituloFS":"20","texto1":"7 horas de fiesta y mucho m\u00e1s","texto1CR":"255","texto1CG":"255","texto1CB":"255","texto1FS":"20","fondo1CR":"255","fondo1CG":"43","fondo1CB":"227","fondo1CA":"90","texto2":"","foto1":"","foto2":"","code":"C\u00f3digo: Isla Blanca","tiempo1":"0000-00-00 00:00:00","tiempo2":"0000-00-00 00:00:00","activo":"2","status":"1","orden":"1"},
    ]
  }
  ,{"type":"table","name":"rel_anuncio","database":"qqx486","data":
    [
      {"id_anuncio":"814","id_categoria":"7","id_subcategoria":"81","orden":"37"},
    ]
  }
  ,{"type":"table","name":"rel_guias","database":"qqx486","data":
    [
      {"id_anuncio":"7","id_guia":"1"},
    ]
  }
  ,{"type":"table","name":"rel_inmuebles","database":"qqx486","data":
    [
      {"id_inmueble":"1","id_caracteristica":"2"},
    ]
  }
  ,{"type":"table","name":"subcategorias","database":"qqx486","data":
    [
      {"id":"1","id_categoria":"1","nombre":"Restaurantes","color":"","activo":"si","orden":"1","promoI":"0","promoF":"0","islas":"3"},
    ]
  }
  ,{"type":"table","name":"subcategorias_porsi","database":"qqx486","data":
    [
      {"id":"1","id_categoria":"1","nombre":"Restaurantes","color":"","activo":"si","orden":"1","promoI":"0","promoF":"0"},
    ]
  }
  ,{"type":"table","name":"subcategorias_textos","database":"qqx486","data":
    [
      {"id_subcategoria":"1","id_idioma":"1","nombre":"Restaurantes","clave":"restaurantes, pizzer\u00edas, los productos de alimentaci\u00f3n, almuerzos, cenas, fiestas, c\u00f3cteles, cocktails, comen, comer, beber, las cocinsa mediterr\u00e1neas, barras, comedores, comiento, sitios para comer, restaurantes especializados en bistecs, el alimento japon\u00e9s, comida japonesa, el alimento espa\u00f1ol, comida espa\u00f1ola, el alimento italiano, comida italiana, parrillas, la cocina francesa, el alimento alem\u00e1n, comida alemana, comidas, licores, mariscos, el alimento asi\u00e1tico, comida asi\u00e1tica, pescados, mariscos, camarones, gambas, tabernas,"},
    ]
  }
  ,{"type":"table","name":"version","database":"qqx486","data":
    [
      {"id":"32"}
    ]
  }
]

【问题讨论】:

  • 能否提供原始 JSON 的样本?我可以从你的代码中猜到它的样子,但不能确定。
  • 我已经用其中的 json 样本编辑了我的问题。

标签: ruby-on-rails ruby database activerecord


【解决方案1】:

看起来AdSubcategory 具有多对多关系。所以rel_anuncio是建立关系的中间表。

由于 json 行的顺序与创建记录所需的顺序不同。

而是尝试首先创建Ads,然后是Categories,最后是Subcategories

json_ads = parsed_json.find { |table| table['name'] == 'anuncios' }
ads = {}

json_ads['data'].each do |ad|
  ads[ad['id']] = Ad.create(
    [... ad fields]
  )
end

Categories 也一样:

json_categories = parsed_json.find { |table| table['name'] == 'categorias' }
categories = {}

json_categories['data'].each do |category|
  categories[category['id']] = Category.create(
    [... category fields]
  )
end

现在您创建了Subcategories,您可以使用HashCategories 来引用它们:

json_subcategories = json.find { |table| table['name'] == 'rel_anuncio' }
subcategories = {}

json_subcategories['data'].each do |subcategory|
  subcategories[subcategory['id']] = Subcategory.create(
    category: categories[subcategory['id_categoria'],
    [... ad fields]
  )
end

rel_anuncio 信息将取决于您如何实现这种关系。

希望对你有帮助。

【讨论】:

  • 感谢 Daniel,种子成功了,id_category 已在子类别表中播种。因此,如果我现在想制作一个 rel_ads 表来处理 resp 之间的 n:n 。类别与广告和子类别与广告。如何让 seed.rb 填充 rel_ads 表?
  • 类似@OKMantis: json_relationships = json.find { |table| table['name'] == 'rel_anuncio' } json_relationships['data'].each do |relationship| RelAd.create( category: categories[relationship['id_categoria']], ad: ads[relationship['id_anuncio']], subcategories: subcategories[relationship['id_subcategoria']], ) end 请把上面的答案标记为正确,如果它解决了您的问题。
  • 当我这样做时,我没有收到任何错误,但是当我查看控制台时,我看到关系(我以这种方式命名表)完全为空。为什么不从 rel_anuncio 拿走任何东西?
  • 它告诉我这个:[1] pry(main)>Relationship.all 关系负载(0.6ms)选择“relationships”。* FROM“relationships”=> []
  • ActiveRecord(当我使用 .create!而不是 .create 时)给了我这个:ActiveRecord::RecordInvalid: Validation failed: Subcategory must exist
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-03-06
  • 2021-04-28
  • 2017-11-06
  • 1970-01-01
  • 2012-12-09
  • 1970-01-01
相关资源
最近更新 更多