→はじめから

”社会人”を”はじめから”した人のあしあと

【技術】ruby on rails でfields_forで画像の初期値を設定する方法

こんにちは。Tedです。
今回はプログラミングについての記事を書こうと思います。

自分の知識の整理と初学者の方が同じところでつまづきそうな気がしたのでここに残しておきます。
私自身調べたところ意外とこれを書いている記事がなかったので役にたつとおもいます。
ご指摘あればガンガンお願いします!

ちなみにソースコードgithubにアップロードしておくので
どうにもこうにもな人は

$git clane リポジトリ名

でクローンしちゃってくだせい!

リポジトリURL:
github.com

概要

投稿の情報をもつPostモデルと投稿に紐づいているImageモデルが親子関係にあるとして
それぞれをフォームで同時に保存する時にサムネイルをつけたい時にどうすれば良いか。
下記のような状態

f:id:travy:20180822222651p:plain

前提

  • 基本的に最近railsを学習しだした初学者の方へ
  • accepts_nested_attributes_forを定義して複数のモデルに対して同時に情報をDBに保存する方法を知っている
  • carrierwave の使い方を知っている

どれも調べるとすぐ出てくるので割愛

railsバージョン4.2.10
他はgithubの内容をご確認ください

準備

$rails new app_name

まずはいつもの

carrierwaveを使って画像を扱うので

gem 'carrierwave'
gem 'mini_magick'

gemをインストール

$bundle install

Postモデルをscaffoldして作成

$rails g scaffold post title:string

Pictureモデルも同様にPostへのリレーションも定義しておきます

$rails g model Picture name:string post:references

マイグレート

$bin/rake db:migrate

画像のアップローダーも作っておきましょう

$rails g uploader pictures

画像をサムネイルっぽくする設定今回はthumbの大きさを使う

  class PicturesUploader < CarrierWave::Uploader::Base
    include CarrierWave::MiniMagick
    process resize_to_fit: [400, 400]
    version :thumb do
      process resize_to_fit: [100, 100]
    end
  ・
  ・
  ・
  end

routes.rbでPictureをネストしちゃいましょう

  resources :posts do
    resources :pictures
  end

それぞれのファイルでリレーションを定義しておきます

class Picture < ActiveRecord::Base
  belongs_to :post
  #これは指定したカラムに対してアップローダを使うための宣言
  mount_uploader :name, PictureUploader
end

class Post < ActiveRecord::Base
  has_many :pictures
  #これでpostのフォーム画面でpicture情報も同時に送信できる
  accepts_nested_attributes_for :images
end

さて、これで諸準備は完了!!
フォーム画面でサムネイルつけて複数同時保存する処理を実装していきましょう!

実装

まずはposts_controller.rbで
同時保存枚数の決め方は今回定数を使って固定していますが別の方法もあるそうです。
今回はここの解説ではないので深くは説明しません。
【挙動】
new,editアクションの処理が始まったら投稿が持っている画像の枚数と
同時保存枚数の差の数だけ投稿に紐づいたpictureをnewする
これで新規入力を生成してくれる

  # 一度に何枚の画像を保存するか決める定数
  PICTURE_COUNT = 3
  def new
    @post = Post.new
    PICTURE_COUNT.times { @post.pictures.build }
  end

  def edit
    count = @post.pictures.count
    (PICTURE_COUNT - count).times { @post.pictures.build }
  end
 ・
 ・
 ・
#ネストしたカラムも送信できるようにストラングパラメーターを設定しておく
  def post_params
    params.require(:post).permit(:title,pictures_attributes: %i[name name_cache])
  end


ここが一番ミソ!!
f.fiels_forでネストしたモデルを定義" :pictures "の部分です
実はこれでも入力自体はできるけど編集時に現存のファイルのサムネイル出したいですよね?
そこでfields_forでは引数(?)にデータを指定することで初期値としてviewに表示することができます!

※コードの後にイメージ画像を載せています

<%= form_for(@post) do |f| %>
 ・
 ・
 ・
  <div>
    <% @post.pictures.each do |picture| %>
      <div class="file-form-box">
        <%= f.fields_for :pictures, picture do |pic| %>
          <%= image_tag picture.name.url(:thumb) if picture.name? %><br>
          <%= pic.file_field :name %>
          <br>
        <% end %>
      </div>
    <% end %>
  </div>
 ・
 ・
end

こんな感じ
f:id:travy:20180822222601p:plain


ちなみに私が書いたコードの定数の部分を変更すると画像入力フォームの数が変わります

終わりに

今回初めて技術ネタを投稿しますのでできるだけわかりやすくなっているはずです
上からコマンドとファイルを編集していけばrails sで同じ挙動が得られるように書いています

もし何か不具合があったりここがわからないということであれば
Twitterやこちらのブログにコメントいただけると幸いです
編集してさらにわかりやすいブログを目指します!

今回の内容は私が自分のサービスを作る上でぶち当たった強大な壁でこちらの内容をググっても
ほとんど検索にかからず苦労したのでこのブログが同じ道を通る方の轍になれば幸いです。

では!