我有一个我觉得很简单的问题,我有这个工作,但我的解决方案感觉不像是 "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 "方法来实现同样的结果。
先说说
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
你看看这个 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
...