2010-11-12 15 views
14

I tienen los siguientes modelosaccepts_nested_attributes_for para enlazar a registro existente, no crea una nueva

class Order < AR::Base 
    has_many :products 

    accepts_nested_attributes_for :products 
end 

class Product < AR::Base 
    belongs_to :order 
    has_and_belongs_to_many :stores 

    accepts_nested_attributes_for :stores 
end 

class Store < AR::Base 
    has_and_belongs_to_many :products 
end 

ahora tengo una vista orden en el que necesito para actualizar las tiendas para el producto. Lo que pasa es que solo quiero conectar los productos a las tiendas existentes en mi db, no crear nuevos.

Mi forma en la vista en orden es el siguiente (utilizando Formtastic):

= semantic_form_for @order do |f| 
    = f.inputs :for => :live_products do |live_products_form| 
    = live_products_form.inputs :for => :stores do |stores_form| 
     = stores_form.input :name, :as => :select, :collection => Store.all.map(&:name) 

Aunque su anidado que trabaja muy bien. El problema es que, cuando selecciono una tienda e intento actualizar la orden (y los productos y las tiendas con ella), Rails intenta crear una nueva tienda con ese nombre. Quiero que solo use la tienda existente y conecte el producto a eso.

Cualquier ayuda apreciada!

EDIT 1:

Al final resuelto este problema de una manera muy crudo:

# ProductsController 

def update 
    [...] 

    # Filter out stores 
    stores_attributes = params[:product].delete(:stores_attributes) 

    @product.attributes = params[:product] 

    if stores_attributes.present? 
    # Set stores 
    @product.stores = stores_attributes.map do |store_attributes| 
     # This will raise RecordNotFound exception if a store with that name doesn't exist 
     Store.find_by_name!(store_attributes[:name]) 
    end 
    end 

    @order.save 

    [...] 
end 

EDIT 2:

solución de Pablo es mucho más elegante y se prefiere en la mina .

+0

Después de revisar la documentación para a_n_a_f (http://api.rubyonrails.org/classes/ActiveRecord/NestedAttributes/ClassMethods.html) llegué por primera vez excitada cuando vi la opción UPDATE_ONLY pero rápidamente di cuenta de que no hay manera hacer lo que quiero hacer (update_only actualiza los objetos existentes antes de crear nuevos). –

Respuesta

21

tratar de implementar un :reject_if que comprobar si la tienda ya existe y luego usarlo:

class Product < AR::Base 
    belongs_to :order 
    has_and_belongs_to_many :stores 

    accepts_nested_attributes_for :stores, :reject_if => :check_store 

    protected 

    def check_store(store_attr) 
     if _store = Store.find(store_attr['id']) 
     self.store = _store 
     return true 
     end 
     return false 
    end 
end 

tengo este código funciona bien en un proyecto actual.

Háganme saber si encuentra una solución mejor.

+0

¡Muy listo! Resolví el problema de una manera mucho menos elegante (editaré mi pregunta para mostrarlo) pero tu solución debería funcionar mejor. –

+8

Esto no tiene sentido para mí. 'self' en' check_store' es el Producto ... y un Producto no tiene una relación 'store' (es HABTM: stores). Entonces, ¿qué hace realmente este código? Además, no parece actualizar la tienda encontrada. – davemyron

+0

Lo modifiqué para que funcione para mi propio uso buscando el registro relacionado existente y actualizando sus atributos * en el reject_if *. Parece hacky, por supuesto, pero funcionó. – davemyron

0

Tuve el mismo problema y lo resolví agregando: id a la lista de parámetros anidados.

def family_params 
    params.require(:family).permit(:user_id, :address, people_attributes: [:id, :relation, :first_name, :last_name) 
end 
+0

Escribí mi pregunta mucho antes de que aparecieran Strong Parameters. –

Cuestiones relacionadas