更新(创建&删除)多个关联的最佳方法(has_many :through)

问题描述 投票:0回答:1

我有一个我觉得很简单的问题,我有这个工作,但我的解决方案感觉不像是 "Rails "的方式。我希望能得到一些见解,如果有一个更容易接受的方式来实现这些结果,而不是我目前的方法,这感觉有点丑陋。

那么,假设我有一个简单的 has_many :through 设置。

# Catalog.rb
class Catalog < ActiveRecord::Base
  has_many :catalog_products
  has_many :products, through: :catalog_products
end

# Products.rb
class Product < ActiveRecord::Base
  has_many :catalog_products
  has_many :catalogs, through: :catalog_products
end

# CatalogProduct.rb
class CatalogProduct < ActiveRecord::Base
  belongs_to :catalog 
  belongs_to :product
end

的数据。Catalog 的数据,以及 Product 除了它们相互关联的事实之外,应该被认为是相互独立的。

现在,让我们说,对于 Catalog我有一个表格,上面有所有的 Products比如说,在前端的一个多检查表单中,我需要能够检查哪些产品与某个目录相关联。在表单字段端,我将返回一个param,它是一个包含所有的 checked 产品。

问题是:现在最被接受的方式是什么?catalog_product 记录,使未选中的产品被删除,新选中的产品被创建,而未改变的产品被单独留下?

我目前的解决方案是这样的。

#Catalog.rb
...
def update_linked_products(updated_product_ids)
  current_product_ids = catalog_products.collect{|p| p.product_id}
  removed_products = (current_product_ids - updated_product_ids)
  added_products   = (updated_product_ids - current_product_ids)
  catalog_products.where(catalog_id: self.id, product_id: removed_products).destroy_all
  added_products.each do |prod|
    catalog_products.create(product_id: prod)
  end
end
...

当然,这将对当前的关联进行比较 计算出哪些记录需要被删除,哪些需要被创建, 然后执行删除和创建。它工作得很好,但如果我需要为一组不同的modelsassociations做类似的事情,我觉得这变得更加丑陋,更不容易。DRY 每当它的实施。

现在,我希望这是 的最佳方法(忽略我的例子中代码的质量,而仅仅是它要实现的目标),我觉得一定有更好的 "Rails "方法来实现同样的结果。

ruby-on-rails activerecord ruby-on-rails-5
1个回答
1
投票

先说说

has_many :products, through: :catalog_products

为您生成一些方法,如 product_ids,检查 这个 下的自动生成方法,以了解更多关于其他生成方法的信息。

所以我们不需要这一行。

current_product_ids = catalog_products.collect{|p| p.product_id}

# exist in both arrays are going to be removed
will_be_removed_ids = updated_product_ids & product_ids 
# what's in updated an not in original, will be appended
will_be_added_ids = updated_product_ids - product_ids  

然后,使用 <<destroy 方法,这些方法也是从关联中生成的 (它让你能够像处理数组一样处理关系),我们将销毁这些方法。will_be_removed_ids,并附上 will_be_added_ids,而不变的将不会受到影响。

最终版本。

def update_linked_products(updated_product_ids)
  products.destroy(updated_product_ids & product_ids)
  products << updated_product_ids - product_ids
end

0
投票

你看看这个 https:/guides.rubyonrails.orgassociation_basics.html#methods-added by-has-many-collection-objects。

如果你已经有了product_ids数组,我想这应该可以。

#Catalog.rb
...
def update_linked_products(updated_product_ids)
  selected_products = Product.where(id: updated_product_ids)
  products = selected_products
end
...
© www.soinside.com 2019 - 2024. All rights reserved.