Accepts_nested_attributes_for для ссылки на существующую запись, а не создавать новую
У меня есть следующие модели
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
Теперь у меня есть вид заказа, где я хочу обновить магазины для продукта.
Дело в том, что я хочу только подключать продукты к существующим магазинам в своем db, а не создавать новые.
Моя форма в представлении заказа выглядит так (с использованием 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)
Несмотря на то, что вложенные в нее файлы работают нормально.
Проблема в том, что, когда я выбираю хранилище и пытаюсь обновить заказ (и продукты и магазины с ним), Rails пытается создать новый магазин с этим именем. Я хочу, чтобы он просто использовал существующий магазин и подключил к нему продукт.
Любая помощь оценивается!
ИЗМЕНИТЬ 1:
В конце концов я решил эту проблему очень грубо:
# 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
ИЗМЕНИТЬ 2:
Решение Пабло гораздо более изящно и должно быть предпочтительнее моего.
Ответы
Ответ 1
Попробуйте реализовать :reject_if
, которые проверяют, существует ли Store и затем его использовать:
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
У меня этот код отлично работает в текущем проекте.
Пожалуйста, дайте мне знать, если вы нашли лучшее решение.
Ответ 2
У меня была такая же проблема, и я решил ее, добавив: id в список вложенных параметров.
def family_params
params.require(:family).permit(:user_id, :address, people_attributes: [:id, :relation, :first_name, :last_name)
end