如何在红宝石的嵌套表单上进行更新?

时间:2018-11-29 20:08:13

标签: ruby-on-rails ruby

在我的应用程序中,我有一个名为User的实体,其中有一个Talent。人才是用户可以在我的系统上(模型,摄影师,视频制作者,客户)的一种

#user.rb

class User < ApplicationRecord
  has_one :talent, dependent: :destroy

人才属于用户,并且具有许多人才能力。

#talent.rb
class Talent < ApplicationRecord
  belongs_to :user
  has_many :talent_talent_abilities, dependent: :destroy
  has_many :talent_abilities, through: :talent_talent_abilities

因此,我们可以创建例如属于Talent的TalentAbility。像这样:

TalentType.create!([
  {name: "Model", is_model: true, is_photo: false, is_makeup: false, is_hair: false},
  {name: "Photographer", is_model: false, is_photo: true, is_makeup: false, is_hair: false

])
TalentAbility.create!([
  {name: "Scuba diving", requires_description: false, talent_type_id: 1}
  {name: "River rafting", requires_description: false, talent_type_id: 1},

我想添加一个视图,该用户根据您的TalentType编辑自己的个人资料,并带有很多复选框,例如“ Scuba Diving-> true”。 “河漂流->错误”。

我的问题是:如何在我的控制器上更新这些关系的更好方法?首先删除属于该人才的所有TalentTalentAbility,然后根据我的表单添加所有人才?

#profiles_controler.rb
def update
 ##delete all the entities
 TalentTalentAbility.where(talent: u.talent).each do |tt| 
   tt.destroy
 end

 ##some code to add the new relationships

end

谢谢

2 个答案:

答案 0 :(得分:1)

我过去做过类似的事情,而且效果很好。不过,我会将其移至模型中,因此您会遇到类似的情况。

class User < ActiveRecord::Base
  ActiveModel::Dirty # if you need to track changes and only delete on attrs changed
  before_save :update_talents

  # ...

  private

  def update_talents
    talents.destroy_all if talents_changed?
  end
end

然后,新人才将与表格数据一起保存。而且,这样您的控制器就不会不必要地混乱。

但是,您应该小心以确保这是您想要的行为。您也可以添加检查以仅在使用ActiveModel::Dirty更改人才的情况下进行更新。可能需要*_changed方法上的语法check进行关联。

注意事项

我倾向于提倡这种方法,因为我的嵌套表单使用JS定位来重新排序其中的项目。可能有一个更明智的方法。

答案 1 :(得分:1)

接受的答案存在问题:

假设您有一个具有5个才能的用户,而他选择了自己已经学会了第六个。如果您采用致电.destroy_all的方式,则会发生以下情况:

  • 5条单独的,连续的DELETE语句发送到数据库
  • 6条单独的,连续的INSERT语句发送到数据库

解决此问题的正确方法是使用相应的ID呈现复选框,并使用_destroy(了解更多here)属性。

简而言之,如果您得到一个包含以下内容的哈希值(很抱歉,您可能需要从表单中获取哈希值,但现在手头没有任何东西可以给您提供AZ示例)像这样:

..., talent_talent_abilities_attributes: [
       {id: 1, _destroy: true}, 
       {id: nil, talent_ability_id: 1}
       {id: 2, talent_ability_id: 2, some_attribute: "value"}
]

然后保存用户,ActiveRecord将:

  • 为第一个项目发布一个DELETE语句。
  • 为第二项发布一个INSERT语句。
  • 取决于是否加载了记录以及id: 2的功能是否有所更改,它可能会或可能不会发出UPDATE语句。

我建议您在rails console中进行一些修改,以创建用户并使用嵌套的属性数组手动更新其功能(再次请参见上述链接,以了解更多信息),并观察其生成的SQL查询数量。如果您还有其他问题,请在此下方留下评论,或者创建一个单独的,更具体的问题(我将争取更多的空闲时间来准备示例,并提供包含实际代码的答案)。