1

В моем приложении, у меня есть несколько clients, и у них есть несколько elements (через has_many_through ассоциация) в зависимости от определенного BusinessType, к которому Client принадлежит так, что вместо того, чтобы вручную добавлять все elements к Client, я можно просто выбрать BusinessType и все будет добавляться автоматически (business_type в Client is attr_readonly). BusinessType HABTM elements.Попадая предыдущих значения HABTM

Вот улов, после создания с по умолчанию 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 метод не работает для HABTM отношений (чтобы получить старые business_type's элементы.

Я попытался с помощью before_update обратного вызова сначала client.elements = client.elements - business_type.elements хранить на мгновение в БД [1,2,3,4,5,6] - [1,2,3] = [4,5,6], и в after_update сделать client.elements = client.elements + business_type.elements, чтобы получить [4,5,6] + [1,3] = [1,3,4,5,6] но это уже новое значение [1,3]. Как я могу получить старый business_type.elements в before_update или after_update?

Заранее благодарим за вашу помощь!

ответ

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, так как это простая реализация, которая работает.

0

Вы должны использовать обратный вызов after_initialize для сохранения предыдущих значений.

after_initialize do @previous_elements = elements.map{|x| x} end 

Обратите внимание, что здесь мы делаем копию ассоциаций по вызову функции карты.