获取以前的HABTM值

时间:2013-06-27 00:36:10

标签: ruby-on-rails-3 activerecord has-and-belongs-to-many before-save after-save

在我的应用中,我有几个clients,他们有几个elements(通过has_many_through关联),具体取决于BusinessType Client属于,以便我可以选择elements而不是手动将所有Client添加到BusinessType,而是自动添加所有内容(business_type Clientattr_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_updateafter_update中获取旧的{{1}}值?

提前感谢您的帮助!

2 个答案:

答案 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。