【问题标题】:How to make an update on a Nested form in ruby?如何在 ruby​​ 中更新嵌套表单?
【发布时间】:2018-11-29 20:08:12
【问题描述】:

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

#user.rb

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

一个 Talent 属于一个用户,拥有很多 TalentAbilities。

#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

谢谢

【问题讨论】:

    标签: ruby-on-rails ruby


    【解决方案1】:

    接受答案的问题:

    假设您有一个拥有 5 种才能的用户,他选择学习了第 6 种才能。如果你打电话给.destroy_all,会发生这样的事情:

    • 5 个单独的、连续的 DELETE 语句发送到 DB
    • 6 个单独的、连续的 INSERT 语句发送到 DB

    此类问题的正确解决方案是使用它们各自的 id 呈现复选框并使用_destroy(阅读更多here)属性。

    简而言之,如果你得到一个包含一些东西的哈希(你可能需要在你从表单中得到它之后清理它,我很抱歉,但我手头没有任何东西可以给你一个 A-Z 的例子)像这样:

    ..., 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 查询。如果您还有其他问题,请在此下方发表评论或创建一个单独的更具体的问题。

    【讨论】:

      【解决方案2】:

      我过去做过类似的事情,效果非常好。不过我会把它移到模型上,所以你会有这样的东西。

      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 更改天赋时才更新。可能想要check *_changed 关联方法上的语法。

      警告

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

      【讨论】:

      • 好主意。我知道如何破坏以前的关系,但是如何更新新的关系?
      • 新的应该与表单中的数据一起自动保存。这是一个before_save 回调,所以新数据应该保持不变。
      • @MarcinKołodziej 就像我说的,应该小心。它很好地满足了我的需求。
      • @MarcinKołodziej 还有其他方式吗?
      猜你喜欢
      • 2016-09-13
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多