Rails ポリモーフィック アソシエーションとネストされたフォームを使用して、in_prices と out_prices (国ごとに 1 つ) を保持する記事を作成しようとしています。
次のようなデータモデルがあります。
# 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 は、新しい記事を作成するときに空の価格フォーム フィールド (国ごとに 1 つ) が表示されるようにするために必要です。
では実際の問題に移ります。作成済みの記事 (in_prices と out_prices が関連付けられている) を編集すると、Rails はこれらのさまざまな種類のポリモーフィックな関連付け (in_prices と out_prices) を区別できなくなります。このため、両方のネストされたフォーム ヘルパーは、関連するすべての価格のフォーム フィールドをレンダリングしますが、これは望ましい動作ではありません。ネストされたフォームの 1 つに in_prices をリストし、もう 1 つに out_prices をリストしたいだけです。
Rails が 2 つの異なるネストされたフォーム ヘルパーで 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
..そして今、すべてが期待どおりに機能します。乾杯!