Rails 画像投稿のやり方(carrierwaveとmini_magick)
スポンサーリンク
こんにちは!
今回は、プログラミングスキル学習のために
画像投稿練習用アプリを作りました。
内容は、
・商品モデルと商品の画像モデルを作成し、1つの投稿フォームで記事とそれに紐づく複数の画像を投稿できる。です。
バージョンの確認。
上のコマンドを入力すると、下にバージョンが出ます。
1 2 |
1 2 |
早速始めていきます。
1 2 3 |
※bin/rails db:createの中にある「bin」とは、
binaryの略でbinary形式で作るというコマンドになってます。
データベースが作成できたら、次はコントローラーです。
1 |
$ bin/rails g controller products
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 |
class ProductsController < ApplicationController
def index
@products = Product.includes(:images).order('created_at DESC')
end
def new
end
def create
end
def edit
end
def update
end
def destroy
end
end
|
次にルートの書いていきます。
①始めは、「ようこそRailsへ」って画面になるので
topのルートを修正。
②さらに、今回の出品機能(product)は、top表示と
投稿(new、create)、編集(edit、update)、削除(destroy)、、、つまり詳細(show)以外を使用するので
以下のように記述します。
1 2 |
root 'products#index'
resources :products, except: :show
|
1行目は、topは「ここですよ」という記述。
2行目は、 出品(product)では、詳細(show)以外を使う。
という記述。
※この「以外」と表す記述が「except」です。
次にproductで必要なviewファイルを作成。
1 2 3 4 5 6 |
products
- index.html.erb
- new.html.erb
- edit.html.erb
- _form.html.erb
- _product.html.erb
|
※このhtml.erbは、
「Rubyが組み込まれたhtmlのようなファイル」という意味。
Railsでviewを作る時は、このようにRubyの記述で作ります。
では、各viewファイルを書いていきます。
まず最低限の見た目を作るため、以下記述。
1 2 3 4 |
<%= link_to '出品', new_product_path %><br>
<div class="contents">
<%= render @products %>
</div>
|
1 2 3 4 5 6 7 |
<div class="content">
<p><%= product.name %></p>
<p><%= product.price %>円</p>
<% product.images.each do |image| %>
<%= image_tag image.src.url %>
<% end %>
</div>
|
render = @products によって、「_product.html.erb」の中身を読み込み、1ページを出力してます。
※「_(アンダースコア)」を始めにつける事で対象のviewファイルをテンプレートにすることができます。
またテンプレート化させることで記述をすっきりさせるだけでなく、修正など管理もしやすくなります。
次に以下2つのファイル内に追記。
1 |
<%= render partial: 'form' %>
|
ここまではview(見た目)ができました。
次はmodel(中身のやりとり)について進めていきます。
1 2 |
①出品情報(product)のモデル作成
②画像情報(image)のモデル作成
これで2つのモデルができました。
また中身の修正とモデル作成した時は、必ず
migrate実行(すぐ気づくけど、よく忘れる)
1 2 |
t.string :name
t.integer :price
|
1 2 |
t.string :src
t.references :product, foreign_key: true
|
できたら
rails db:migrateコマンドを実行。
ちゃんとできたか不安な時、
ターミナルにできたかエラーか書いているが!
僕のように英語得意じゃない、もしくはターミナルに書いている文章が呪文のように見える方は、
rails db:migrate:statusとコマンドを入れると
対象のmigrationファイルがUP(できてる)か
DOWN(できてない)か分かります。
またmigrateしたけど、記述間違えた!というときには
rails db:rollbackコマンドを実行。
すると1つ前の物がDOWNに戻ります。
※このDOWN状態の時のみ修正ができるので、間違えて直したい時はこの手順で進めます。
修正が終わったら、再度
rails db:migrateコマンドを実行。
※ファイルがUP状態でないとエラー出ます。
次は、必要なgem(ジェム)を入れます。
gemとは、
ruby(ルビー)という言語の中にインストールする、gem(宝石)という便利ツールのことです。
今回入れる2種類のgemだけでなく、とてもたくさんの便利なgemがあります。
今後もブログ更新しながらgemの紹介もしていきますのでぜひ見てみてください。
では、手順です。
やり方は簡単! 対象の場所に書いて、インストールするだけ!
以下、ファイルの最下部に記述。
Gemfile
1 2 |
gem 'carrierwave'
gem 'mini_magick'
|
できましたら、あとはターミナルで
bundle installとコマンドを打つだけ!(bundleだけでも行ける)
これでgemがインストールできました。
続いて、今回入れたgemを使うための設定をしていきます。
まずは
$ rails g uploader image
uploaderを作成します。
できたファイル等を修正していきます。
1 2 3 |
include CarrierWave::MiniMagick // この記述を探し、コメントアウトを外す
process resize_to_fit: [100, 100] // この記述は追記
|
モデルファイルもそれぞれが正しく紐づくように
追記していきます。
1 |
has_many :images
|
1 2 |
mount_uploader :src, ImageUploader
belongs_to :product
|
※has_manyは、productからimageをみた時、
ひとつ出品(product)に対して、複数の画像(image)があるのでこの記述をします。 対象が複数なので英語の複数形でimagesと記述します。
※対してbelongs_toは、imageからproductをみた時、
たくさんの画像をひとつの出品に紐付ける仕様にするので、この場合はこの記述を使います。 相手は常に単数なのでここでは複数形にあたる「s」は付けません。
初めはこの使い分けが分からなかったので、復習のため書きました。
ここから画像投稿機能の本格的なところを実装していきます。
※今回は、次回に続く複数枚画像を投稿したり、プレビューしたり機能追加予定のため、通常と違う記述をしていきます。
そこだけ注意しながらみていただけたらと思います。
では最初に、使うヘルパーメソッド
fields_for
複数の別のリソースを同時に保存する際に利用。
accepts_nested_attributes_for
fields_forとセットで使用。 親モデルに書くことで
モデルの親子関係を作ります。
allow_destroy: true
accepts_nested_attributes_forメソッドのオプション。 親のレコードが削除されると、紐づいた子のレコードも削除することができます。
上記をもとに記述していきます。
1 |
accepts_nested_attributes_for :images, allow_destroy: true
|
1 2 3 4 |
def new
@product = Product.new
@product.images.new
end
|
newとeditで読み込むテンプレートの中身を記述。
1 2 3 4 5 6 7 8 |
<%= form_for @product do |f| %>
商品名<%= f.text_field :name %><br>
価格<%= f.number_field :price %><br>
<%= f.fields_for :images do |i| %>
<%= i.file_field :src %><br>
<% end %>
<%= f.submit %>
<% end %>
|
ここで使うfields_forによって親(product)に紐づく子(image)が投稿の数だけ生成されていく形ができます。
最後に投稿までの動きをコントローラーに追記すれば、完成です。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
def create
@product = Product.new(product_params)
if @product.save
redirect_to root_path
else
render :new
end
end
|
fields_for
を利用して作成されたフォームから来る値は、○○s_attributes: [:××]
という形でparamsに入ります。○○
は関連付く側のモデルの名前、××
にはフォームに対応するカラムの名前が入ります。
最後までお付き合いいただきありがとうございます!
次回は、ここをベースに複数枚画像投稿機能の実装につなげていきますので次回もよろしくお願いします。
あ