Prog-me.

Rails中心、機械学習も、インフラもセキュリティも

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, ...])

-------------------------------------

でとれる。