1.複数画像アップロード機能を実装
carrierwaveを使用して複数枚の画像をアップロードできるように実装してみた。
carrierwaveとは?
carrierwaveとは、Railsアプリケーションから画像アップロード機能を簡単に実装できるライブラリ。今回は、carrierwave ver2.1.0を使用しました。
どのように使用したか?
まずは、下のGemをインストールする。
gem 'carrierwave'
gem 'mini_magick'
アップローダーを生成する。
rails g upload image
これにより次のファイルが生成される。このファイル内でカスタマイズしたいときは処理を加える。
app/upload/image_upload.rb
なので、自分は下のように設定を行いました。
class ImageUploader < CarrierWave::Uploader::Base
include CarrierWave::MiniMagick
process resize_to_fill: [1000, 1000]
version :thumb do
process resize_to_fit: [223,223]
end
version :swiper do
process resize_to_fit: [400, 400]
end
version :thumbnil do
process resize_to_fit: [100, 100]
end
storage :file
def store_dir
"uploads/#{model.class.to_s.underscore}/#{mounted_as}/#{model.id}"
end
def extension_whitelist
%w(jpg jpeg gif png)
end
end
どのように設定を加えていったかというと、、、
include CarrierWave::MiniMagick
アップロード時に画像のリサイズを行いたかったので、minimagickをインストール。image_upload.rb生成時にコメントアウトで記載してあるので#を消して処理コードとして記載。minimagickとは、CプログラムであるimagemagickのRubyのインターフェース。これによって、画像リサイズ用のメソッドを使用することが出来る。
下の処理は、アップロードされるとと、1000×1000pxで切り抜きを行い、次にthumbと呼ばれるバージョンが作成され、223×223pxに拡大縮小される。同じように、swiper、thumbnilと呼ばれるバージョンが作成され、各々のバージョンに拡大縮小される。
※ただし、チーム開発によってはあまりバージョンを増やすのは好ましくないとのこと。
process resize_to_fill: [1000, 1000]
version :thumb do
process resize_to_fit: [223,223]
end
version :swiper do
process resize_to_fit: [400, 400]
end
version :thumbnil do
process resize_to_fit: [100, 100]
end
これは、画像がアップロードした時に保存される場所である。デフォルト記載されている。「public/uploads/指定したモデル名/指定したモデルのカラム名/モデルID/画像と各バージョンで作成した画像」のように置かれている。変更した場合は、オーバライドして記載すれば良い。
def store_dir
"uploads/#{model.class.to_s.underscore}/#{mounted_as}/#{model.id}"
end
これもデフォルトでコメントアウトで記載されているので処理出来るように記載。許可される拡張機能のホワイトリストを指定することが出来る。jpg、jpeg、gif、png以外の拡張子をアップロードするとレコードが無効になる。
def extension_whitelist
%w(jpg jpeg gif png)
end
ここまでで設定の説明は終わりにして、次に親となるpostテーブルと子のimageテーブルを作成する。
postとimageでテーブルを分けたのは、複数投稿に対応する為。
posts |
---|
content |
images |
---|
url |
post_id |
$rails g model Post content:text
$rails g model Image url:string post:reference
ここでつまずいたのが、自分の場合はimageモデル作成の際にjson型を扱ったことです。 もともと、postテーブル内でimageカラムを作成して複数投稿できる仕様にしようと思ったのですが、新しいimageテーブルを作成して保存するよう変更したため、わざわざjson型にしなくても良いということを後になって気づきました。なので、ここで一つのテーブルで複数画像を扱うならjson型にして、一つのオブジェクトレコードに複数画像を扱えるように設計するのもいいと思います。自分の場合は、別のテーブルを作成してjson型のままにしていますが、特に理由がないのならstring型で作成することをお勧めします。
マイグレーションファイルを作成して、データベースを更新する。
$rails db:migrate
モデルファイルに以下の記述を加える。
class Image < ApplicationRecord
belongs_to :post
mount_uploader :url, ImageUploader #アップロード機能を使いたいデータにマウントする。
end
class Post < ApplicationRecord
validates :content, presence: true, length: { maximum: 1000 }
has_many :images, dependent: :destroy
accepts_nested_attributes_for :images #postを投稿するとimageも同時に投稿できるようになる
end
ここで注意しなければならないのは、accepts_nested_attributes_forを使うときは、ストロングパラメータにimages_attributesカラムを追記しなければならないこと。以下のようになります。
def new
@post = Post.new
@image = @post.images.build
end
def create
@post = current_user.posts.new(post_params)
if @post.save
redirect_to posts_path, success: "投稿しました"
else
flash[:danger] = "投稿に失敗しました"
render :new
end
end
private
def post_params
params.require(:post).permit(:content, images_attributes: [:url])
end
これで複数画像をパラメーターとして渡せるように設定できました。
続いて、viewで画像をどのように複数投稿できるようにするか考えていきます。
ここで、自分は色々ハマまりました。fields_forメソッドでは、第2引数にmultiple: trueを記述することで複数投稿できるとのことですが、うまくいかず、、、。なので別の方法として、javascriptで複数投稿できるように実装しました。この記事がとてもよく書かれていたので参考にさせていただきました。→Qiita この記事の通りに設定すれば、javascriptが起動して、アップロードするたびにプログラムが動いてくれるはずです。
2. swiperで1つの投稿に対して複数画像をスライドできるように実装
swiperとは?
ざっくりというと、スライド機能の実装が簡単にできるフレームワーク。
どのように使用したか?
まずは、アプリケーション内でswiperを使えるように設定します。いくつか方法があるのですが、私はyarnを利用して導入しました。こちらの記事のyarnでの導入方法や内容がとても分かりやすかったので参考にさせていただきました。
→Qiita
swiperをyarnで導入します。
$yarn add swiper
$yarn install
導入できたか確認するには、packege.json を確認してください。もしyarnを導入していないのであれば、下記のコマンドでyarnを導入してください。(macをお使いの場合)
$brew installl yarn
導入したら、application.js、application.scssに下記のように記載します。
@import "swiper/swiper-bundle";
//= require swiper/swiper-bundle.js
//= swiper.js
swiper.jsファイルを作成し、下記のように記述してください。swiperでは、swiperで加えたい種類のスライド方法を自分で記述し作成する必要があります。swiperのデモから自分のお好みのスライド方法を選び、ソースコードから!-- Initialize Swiper --より下のスクリプト内のjsのコードをコピペしてください。スクリプトタグは記載する必要はありません。私の場合は、ページネーション/動的弾丸でのスライドにしたので下記のようになります。このjsファイル名はswiper.jsでなくても構いません。ファイル名を変更したい場合は、applicaion.js内で記載したファイル名も変更してください。デモ
var swiper = new Swiper(".swiper-container", {
pagination: {
el: ".swiper-pagination",
dynamicBullets: true,
},
});
これで準備は整ったので、viewで実際に実装してみます。
ページネーション/動的弾丸での実装例なので他のスライド方法を選んだ方は、ソースコードを確認してください。
.swiper-container.top-carousel
.swiper-wrapper(style="transform: translate3d(0px, 0px, 0px)")
- @post.images.each do |img|
.swiper-slide(style="width: 400px;")
= link_to post do
= image_tag img.swiper.url, class: "card-img-top"
.swiper-pagination
~省略~
= javascript_include_tag "application"
ここで大事なのは、= javascript_include_tag "application"を一番最後に記述することです。これを書き忘れるとswiperが起動してくれません。application.html.slimに書くという方法もありますが、自分はswiperを必要とするページの部分だけに記述してます。また、このimg.url.swiper.urlは、carrierwaveで作成したswiperバージョンの画像を呼び出しています。
これで、自分の場合はswiperを実装することができました。