在我的应用中,我有几个clients
,他们有几个elements
(通过has_many_through
关联),具体取决于BusinessType
Client
属于,以便我可以选择elements
而不是手动将所有Client
添加到BusinessType
,而是自动添加所有内容(business_type
Client
是attr_readonly
)。 BusinessType
HABTM elements
。
这是捕获,在使用默认的BusinessType
创建后,客户端可以更新其元素并根据需要删除或添加(主要是添加),所以我要做的是以下内容:
假设一个business_type
包含元素[1,2,3]
并分配给一个client
,则会将以下元素手动添加到client
= [4,5,6]
,以便它最终得到[1,2,3,4,5,6]
,确定一切都很好。
但在此之后,business_type
会更新并删除元素2
,因此最终成为[1,3]
。这是交易,我希望通过移除2
而不是与[4,5,6]
相对应的business_type
来更新客户端,以便最终[1,3,4,5,6]
after_update
我正在使用clients'
回调来更新_was
元素,但business_type's
方法不适用于HABTM关系(以获取旧的before_update
元素。< / p>
我尝试使用client.elements = client.elements - business_type.elements
回调首先将[1,2,3,4,5,6] - [1,2,3] = [4,5,6]
暂时存储在数据库client.elements = client.elements + business_type.elements
中,然后在after_update执行[4,5,6] + [1,3] = [1,3,4,5,6]
以获取[1,3]
但是这已经是business_type.elements
的新值。如何在before_update
或after_update
中获取旧的{{1}}值?
提前感谢您的帮助!
答案 0 :(得分:1)
我在应用程序中遇到了类似的问题,我能想到的唯一解决方案是在控制器中执行update_attributes之前存储值。
示例代码:
模型
class Product < ActiveRecord::Base
has_and_belongs_to_many :categories, :join_table => "categories_products"
def remember_prev_values(values)
@prev_values = values
end
def before_update_do_something
puts @prev_values - self.category_ids # Any categories removed?
puts self.category_ids - @prev_values # Any categories added?
end
end
class Category < ActiveRecord::Base
has_and_belongs_to_many :products, :join_table => "categories_products"
end
在产品控制器的更新方法中,我执行以下操作:
class ProductsController < ApplicationController
...
def update
@product.remember_prev_values(@product.category_ids)
if @product.update_attributes(params[:product])
flash[:notice] = "Product was successfully updated."
redirect_to(product_path(@product))
else
render :action => "edit"
end
end
...
end
这不是理想的,但是可以在执行之前“捕获”habtm插入/删除。
我确实认为可以在回调中做,但你可能需要“入侵”ActiveRecord。
我没有花太多时间去尝试深入研究ActiveRecord内部,因为这是一个有效的简单实现。
答案 1 :(得分:0)
您应该使用after_initialize回调来存储以前的值。
after_initialize do @previous_elements = elements.map{|x| x} end
请注意,我们在这里通过map函数调用复制assosiations。