【技術】ruby on rails でfields_forで画像の初期値を設定する方法
こんにちは。Tedです。
今回はプログラミングについての記事を書こうと思います。
自分の知識の整理と初学者の方が同じところでつまづきそうな気がしたのでここに残しておきます。
私自身調べたところ意外とこれを書いている記事がなかったので役にたつとおもいます。
ご指摘あればガンガンお願いします!
ちなみにソースコードはgithubにアップロードしておくので
どうにもこうにもな人は
$git clane リポジトリ名
でクローンしちゃってくだせい!
リポジトリURL:
github.com
概要
投稿の情報をもつPostモデルと投稿に紐づいているImageモデルが親子関係にあるとして
それぞれをフォームで同時に保存する時にサムネイルをつけたい時にどうすれば良いか。
下記のような状態
前提
- 基本的に最近railsを学習しだした初学者の方へ
- accepts_nested_attributes_forを定義して複数のモデルに対して同時に情報をDBに保存する方法を知っている
- carrierwave の使い方を知っている
どれも調べるとすぐ出てくるので割愛
準備
$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
こんな感じ
ちなみに私が書いたコードの定数の部分を変更すると画像入力フォームの数が変わります