Rails与正确验证的多对多关联并保存所有

时间:2016-01-10 15:07:53

标签: ruby-on-rails ruby-on-rails-4

在我的Rails 4.2.5应用程序中,我有以下两个与关联模型(Spellcategory)具有多对多关系的模型(Spell,Category):

class Spell < ActiveRecord::Base
    has_many :spellcategories, class_name: "Spellcategory", foreign_key: "spell_id", dependent: :destroy
    has_many :categories, through: :spellcategories, source: :category
end

class Category < ActiveRecord::Base
    has_many :spellcategories, class_name: "Spellcategory", foreign_key: "category_id", dependent: :destroy
    has_many :spells, through: :spellcategories, source: :spell
end

class Spellcategory < ActiveRecord::Base
    belongs_to :spell, class_name: "Spell"
    belongs_to :category, class_name: "Category"
end

我已经有一个现有的类别列表,想要导入一个法术列表。因为在导入过程中可以手动输入,所以我想首先创建所有内容,显示它,然后完全保存所有内容(拼写+链接到类别)。 我将对象存储在activerecord-session_store中,从第一步到第二步。

我在第一步中使用XML文件中的以下代码加载对象(有点伪代码,因为我不想让你厌烦所有的XML解析):

spells = xml_doc.path(...).map do |xml_spell|
    new_spell = @user.spells.build
    xml_spell.path('cats/cat').each do |node|
       new_spell.categories << Category.find_by(name: node.text) 
    end
    new_spell
end

并在第二步中保存所有法术。

if spells.map(&:valid?).all?
    spells.each(&:save!)
end

最后一行失败,因为验证失败,错误 Spellcategories无效。 我的猜测是它与关联表中未保存的子元素有关。我试图使用:autosave,但它没有解决问题。

我做错了什么导致我无法一次性保存?

1 个答案:

答案 0 :(得分:0)

如果您不需要访问Spellcategory模型本身,则可以使用has_and_belongs_to_many代替两个has_many,这会简化相当多的事情。

如果确实需要,可以在问题评论中概述问题的原因 - 您没有创建Spell的ID,以便能够保存与之关系。这是我要尝试的 - 两个选项:

选项1 。如果您只有几条记录:

Spell.transaction do
  spells = xml_doc.path(...).map do |xml_spell|
    new_spell = @user.spells.create
    xml_spell.path('cats/cat').each do |node|
       new_spell.categories << Category.find_by(name: node.text) 
    end
    new_spell
  end
end

将其包装到事务中可确保一致性。替换&#34;构建&#34;用&#34;创建&#34;在添加类别之前初始化拼写记录。

选项2 。如果你有很多记录。我用这种方法导入了数百万条记录。保留连接表类,然后使用批量导入插件(如https://github.com/zdennis/activerecord-import)来加载数据。