使用 update_attributes() 和 has_many :through 关联时出现重复记录

发布于 2024-12-15 14:11:20 字数 896 浏览 2 评论 0原文

我不明白为什么它会生成重复的recruit_profiles_skills而不是更新

class RecruitProfile < ActiveRecord::Base
   has_many :skills, :through => :recruit_profiles_skills
   has_many :recruit_profiles_skills, :dependent => :destroy
   accepts_nested_attributes_for :recruit_profiles_skills, :allow_destroy => true

class Skill < ActiveRecord::Base
    has_many :recruit_profiles, :through => :recruit_profiles_skills
    has_many :recruit_profiles_skills, :dependent => :destroy

参数看起来像

"recruit_profile"=>{
    "recruit_profiles_skills_attributes"=>[{"skill_id"=>"1", "level"=>"15"}]
}

然后我这样做

def update
    @recruit_profile.update_attributes(params[:recruit_profile])

但是,这会创建重复的关联记录。为什么这不简单地更新!? 我可以使用验证来防止重复项,但它永远不会更新,因为它只想创建新记录,但新记录无效,因为它未通过验证。

I can't figure out why it's generating duplicate recruit_profiles_skills instead of updating.

class RecruitProfile < ActiveRecord::Base
   has_many :skills, :through => :recruit_profiles_skills
   has_many :recruit_profiles_skills, :dependent => :destroy
   accepts_nested_attributes_for :recruit_profiles_skills, :allow_destroy => true

class Skill < ActiveRecord::Base
    has_many :recruit_profiles, :through => :recruit_profiles_skills
    has_many :recruit_profiles_skills, :dependent => :destroy

Params looks like

"recruit_profile"=>{
    "recruit_profiles_skills_attributes"=>[{"skill_id"=>"1", "level"=>"15"}]
}

Then I do

def update
    @recruit_profile.update_attributes(params[:recruit_profile])

But, this creates duplicate association records. Why does this not simply update!?
I can prevent the duplicates using validations, but then it never updates since it just wants to create a new record, but the new record is invalid because it fails the validation.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

温柔戏命师 2024-12-22 14:11:20

我在代码中解决此问题的方法是:

  1. 在已创建的每个属性中包含关联表中行的“id”。这使得更新能够按预期进行。
  2. 使用 Skill_id 属性上的复选框。因此,如果未选中该复选框,则 Skill_id 将不会显示在 params 哈希中。然后,我运行这段代码

params[:recruit_profile][:recruit_profiles_skills_attributes].map{ |rps| if rps[:skill_id].nil? then rps[:_destroy] = 1 end }

该段代码将检查 :skill_id 是否已设置。如果未设置,则需要删除该行。即使 :allow_destroy 设置为 true,删除条目的方法也是将“:_destroy => 1” key=> value 附加到哈希中。因此, :id 将出现,并且 :_destroy 将出现,因此 update_attributes 将删除它。

执行上述操作将允许创建(:id 不存在,但 :skill_id 存在)、更新(:id 存在且 :skill_id 存在)和销毁(:id 存在,但 :skill_id 不存在)。恕我直言,这不是它应该如何工作的,但是只需要额外的 1 行代码就可以完成工作(由于长度

而分成 3 行)。(注意:将 Skill_id 替换为中的任何其他参数仅当您使用具有多个属性的关联表时才需要这种方式,否则经典的 collection_ids = [#,#,#] 仍然适用于 has_many :through 关联。)

The way I solved this problem in code was to:

  1. Include the 'id' of the row in the association table in every attribute that has already been created. This allows for the updating to work as expected.
  2. Use a checkbox on skill_id attribute. Thus, if the checkbox is not checked, the skill_id will not show up in the params hash. Then, I run this bit of code

params[:recruit_profile][:recruit_profiles_skills_attributes].map{ |rps| if rps[:skill_id].nil? then rps[:_destroy] = 1 end }

That bit of code will check to see if the :skill_id is set. If it is not set, then the row needs to be deleted. The way to delete entries, even if :allow_destroy is set to true, is to append a ":_destroy => 1" key=>value to the hash. Thus, the :id will be present, and a :_destroy will be present, so update_attributes will delete it.

Doing the above will allow for create (:id not present, but :skill_id present), update (:id present and :skill_id present) and destroy (:id present, but :skill_id not present). IMHO, that isn't how it should work, but the job gets done with only 1 extra line of code (split in to 3 lines because of length).

(NOTE: replace skill_id with whatever other parameter is also in your association table. This round about way is only needed if you're using association tables with multiple attributes. Otherwise, the classic collection_ids = [#,#,#] still works with has_many :through associations.)

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文