Ruby
Rails
fields_for

fields_forの上手な使い方

fields_forの使い方をマスターしよう

※本記事は子モデルの画像を編集する場合を想定しています。

誰のための記事か

・fields_forの使い方がわからない
・新規登録はできるがレコードの更新ができない

そもそもfields_forとは

form_for内で異なるモデルを編集できるようになる。

fields_forを使うことによって異なるモデル(子モデル)を編集できるようになる。
例:Articleモデルに紐付くImageモデル

newで使う

フォーム

_form.html.erb
<%= form_for @article do |f| %>

  <%= f.text.field :title %>

  <%= f.fields_for :images do |image| %>
    <%= image_tag(image.object.content) %> #画像があれば表示する
    <%= image.file_field :content %>
    <%= image.hidden_field :id, value: image.object.id %> #編集時にはidが必要らしい
  <%= f.submit %>

<% end %>

コントローラ

articles_controller.rb
def new
  @article = Article.new
  @article.images.build
end

def create
  @article = current_user.articles.build(article_params)
  @article.save
end

def article_params
  params.require(:article).permit(:title, images_attributes: [:content])
end

モデル

article.rb
has_many :images
accepts_nested_attributes_for :images
image.rb
belongs_to :article
mount_uploader :image, ImageUploader

これで画像を子モデルに保存することができます。

editで使う

フォーム

_form.html.erb
#フォームはnewと同じです

<%= form_for @article do |f| %>

  <%= f.text.field :title %>

  <%= f.fields_for :images do |image| %>
    <%= image_tag(image.object.content) %> #画像があれば表示する
    <%= image.file_field :content %>
    <%= image.hidden_field :id, value: image.object.id %> #編集時にはidが必要らしい
  <%= f.submit %>

<% end %>

コントローラ

articles_controller.rb
def edit
  @article = Article.find(params[:id])
end

def update
  @article.update(update_article_params)
end

def update_article_params
  #update時は[_delete]と[id]が必要
  params.require(:article).permit(:title, images_attributes: [:content, :_destroy, :id])
end

モデル

article.rb
#もちろんモデルもnewと同じ
has_many :images
accepts_nested_attributes_for :images
image.rb
#もちろんモデルもnewと同じ
belongs_to :article
mount_uploader :image, ImageUploader

これだけで画像の更新ができてしまいます。

最後に

fields_forの使い方は意外と難しく、記事もあまり数がありません。
少しでも皆様のお役に立てば幸いです。

参考文献

http://railsdoc.com/references/fields_for