我正在尝试使用rails多态关联和嵌套表单创建一个包含in_prices和out_prices(每个国家一个)的文章。
我有一个看起来像这样的数据模型:
# app/models/article.rb
class Article < ActiveRecord::Base
has_many :out_prices, :class_name => "Price", :as => :priceable
has_many :in_prices, :class_name => "Price", :as => :priceable
end
# app/models/price.rb
class Price < ActiveRecord::Base
belongs_to :priceable, :polymorphic => true
end
# db.schema for prices
create_table "prices", :force => true do |t|
t.integer "value"
t.integer "country_id"
t.integer "priceable_id"
t.string "priceable_type"
end
使用嵌套表单创建文章及其关联,如:
# app/views/articles/_article_form.html.erb
<%= form_for setup_article(@article) do |f| %>
<%= f.fields_for :in_prices do |ff| %>
<%= ff.text_field :value %>
<% end %>
<%= f.fields_for :out_prices do |ff| %>
<%= ff.text_field :value %>
<% end %>
<% end %>
setup_article方法是构建关联的辅助方法:
# app/helpers/articles_helper.rb
def setup_article(article)
if article.in_prices.nil?
# Setup one in price for each country
Country.all.each do |country|
article.in_prices.build(:value => 0, :country_id => country.id)
end
end
if article.out_prices.nil?
# Setup one out price for each country
Country.all.each do |country|
article.out_prices.build(:value => 0, :country_id => country.id)
end
end
article
end
需要setup_article以确保在创建新文章时显示空的价格表单字段(每个国家/地区一个)。
现在到了实际问题。当我编辑已经创建的文章(其中包含in_prices和out_prices)时,Rails将无法区分这些不同类型的多态关联(in_prices和out_prices)。因此,两个嵌套的表单助手都会为所有关联的价格生成表单字段,这不是所需的行为。我只想在其中一个嵌套表单中列出in_prices,在另一个表单中列出out_prices。
如何配置这些关联以确保rails可以区分两个不同嵌套表单助手中的in_prices和out_prices关联?
编辑( 已解决 )
我的一位朋友指出我需要在价格表中添加另一个字段来标记它的价格类型。我将此字段称为price_type,db.schema最终看起来像这样:
# db.schema for prices
create_table "prices", :force => true do |t|
t.integer "value"
t.integer "price_type"
t.integer "country_id"
t.integer "priceable_id"
t.string "priceable_type"
end
注意:请勿将此字段命名为“type”,因为这是保留名称。
'price_type'字段可以通过在嵌套表单中添加隐藏字段(安全性较低)来填充,也可以在保存文章及其关联数据之前在控制器中处理它。我选择将它添加为隐藏的参数:
# app/views/articles/_article_form.html.erb
<%= form_for setup_article(@article) do |f| %>
<%= f.fields_for :in_prices do |ff| %>
<%= ff.text_field :value %>
<%= ff.text_field :price_type, :value => "in" %>
<% end %>
<%= f.fields_for :out_prices do |ff| %>
<%= ff.text_field :value %>
<%= ff.text_field :price_type, :value => "out" %>
<% end %>
<% end %>
为确保正确过滤关联,需要使用':conditions'标记声明,例如:
# app/models/article.rb
class Article < ActiveRecord::Base
has_many :out_prices, :class_name => "Price", :as => :priceable, :conditions => { :price_type => "in" }
has_many :in_prices, :class_name => "Price", :as => :priceable, :conditions => { :price_type => "out" }
end
..现在一切都按预期工作了。干杯!