Polymorphicなモデル&それに対応したネストしたフォームを作る!
そもそもpolymorphicとはなにか。
例えばユーザーと商品がそれぞれ画像を持つときの、画像モデル。いちいちユーザ画像モデルと商品画像モデルを作るのは二度手間な気がする...。
そんなときPolymorphicにすると、ユーザモデルと商品モデルそれぞれに画像モデルを従属(belongs_toの関係)させることができる。
画像モデルはユーザの子でもあり、商品の子でもある。つまり、@user.imagesも@product.imageもできてしまうのだ。
-----------------------------
class User < ActiveRecord::Base
has_many :images, :as=> :imageable #imageableという名前で親モデル(User)を抽象化している。
class Product < ActiveRecord::Base
has_one :image, :as => :imageable #imageableという名前で親モデル(Product)を抽象化している。
class Image < AcriveRecord::Base
belongs_to :imageable, :polymorphic => :true #抽象化された親モデル(imageable)に従属している。
-----------------------------
さてしかしこれだけだと、Images データベースに値が入って、ProductなのかUserなのかわからないということが起こりうる。
なので、imagesDBに
imageable_type #=> ProductかUserかを判別するため。今回は"Product"か"User"の文字列を入れる
imageable_id #=> productかuserのIDを入れる。
という2つのカラムを足す。
これでモデルの関係を示す記述が完成した。
次はこのモデル関係に対応して、商品のDBと画像のDB両方に一気にレコードを入れるフォームを作る。
ネストしたフォーム(この場合は商品フォームの中に画像フォーム)を作る場合は、accepts_nested_attributes_forをモデルに追加する。
------------------------------------
class Product < ActiveRecord::Base
has_one :image, :as => :imageable
accepts_nested_attributes_for :image
end
-------------------------------------
これで何ができるかというと、viewで
-------------------------------------
<%= form_for @product do |p| %>
<%=p. text_field :name %>
・・・
<%=p.fields_for :image, @product.image || Image.new do |i| %> #=>ネストした画像フォーム
<% if @product.image.present? %>
<%= image_tag @product.image.image.url %>
<% end %>
<br/>
<%= i.label :image %>
<%= i.file_field :image %>
<%= i.hidden_field :imageable_type, value: "Product" %>
<%= i.hidden_field :imageable_id, value: @product.id %>
<% end %>
・・・
-------------------------------------
パラメータはどうなるのかというと、
iamge_attributes の中に imageとか、imageable_typeとかが詰まっている形になるので、
-------------------------------------
params.require(:product).permit(:name,....., :image_attributes => [:image, :imageable_type, :imageable_id, ...])
-------------------------------------
でとれる。