我有以下两种模式:
class Product < ActiveRecord::Base
belongs_to :shop
validates_numericality_of :price, :greater_than_or_equal_to => 0
end
class Shop < ActiveRecord::Base
has_many :products
validates_presence_of :name
end
以下是create
的{{1}}方法:
ProductsController
当用户添加新产品时,他有一个选择框来选择商店。此选择框中的最后一个选项允许用户添加新商店(显示另一个输入文本字段)。最后一个选项的def create
if params[:product][:shop_id] == "new_shop"
@shop = Shop.find_by_name(params[:new_shop]) || Shop.create(:name => params[:new_shop]) # Is there a simpler method to do this ?
params[:product][:shop_id] = @shop.id
end
@product = Product.new(params[:product])
if @product.save
redirect_to(:action => 'index')
else
render('new')
end
end
为value
。
如果新输入的商店的验证失败,我希望产品的验证失败并显示适当的错误(目前只有在产品本身的验证失败时才会显示错误。)
实现这一目标的最“Rails 3方法”是什么?
答案 0 :(得分:4)
我认为如果你使用accepts_nested_attributes_for
会更简单。所以对你的Product
模型添加:
accepts_nested_attributes_for :shop
然后在视图中,根据您的选择列表值,您可以修改表单(以js为单位),因此商店将有shop_id
字段或整套文件:
<% f.fields_for :shop do |sf| %>
...
<% end %>
然后,如果用户选择现有商店,它只会传递shop_id
,但如果用户选择新商店,那么表单也会传递新的关联对象。
如果您希望商店名称是唯一的,则只需将validates_uniqueness_of
添加到Shop
型号。
如果商店验证失败,则不会保存产品。基本上,你的控制器保持尽可能简单(只需从params创建新的产品对象 - 你不关心在那里购物)。
答案 1 :(得分:2)
我同意@klew,你应该使用accepts_nested_attributes_for
。
但是,对您的问题的简单直接回答是使用validates_associated
。
此外,更好的方式:
@shop = Shop.find_by_name(params[:new_shop]) || Shop.create(:name => params[:new_shop])
将是:
@shop = Shop.find_or_create_by_name(params[:new_shop])