前 基礎Ruby on Rails #21 Chapter12 アセット・パイプライン
次 基礎Ruby on Rails #23 Chapter13 複数画像のアップロード/順番の入れ替え
Active Storageとは
Active Storageのしくみ
- Rails 5.2で導入された機能
- Amazon S3、Google Cloud Storage、Microsoft Azure Storage等のクラウドスレレージへ簡単にアップロードできる。
- クラウドストレージに保存されたファイルを配信する手段も提供する。
- 事前署名付きURLにより配信され、有効期限(5分)が設定されている。一般に公開された状態にはならない。
ディスクサービス
- Active Storageは、ローカルサーバーのディスクにファイルをアップロードすることもできる。アップロード先をディスクサービスという。
- ディスクサービスも個別のURLが与えられ、リダイレクションが行われるが、有効期限は設定されない。
セットアップ手順
ImageMagickのインストール
- Active Storageには画像のサイズを変換する機能があり、利用するにはImage Magickが必要なので、インストールする。
WSL/Ubuntu
$ sudo apt-get install -y imagemagick
Mac
$ brew install imagemagick
Gemパッケージmini_magickの導入
- mini_magickを導入するために、Gemfileのコメントアウトを外す。
Gemfile(一部)
# Use ActiveStorage variant
gem 'mini_magick', '~> 4.8'
$ bundle install
マイグレーションスクリプトの生成と実行
- 以下のコマンドを実行して、Active Storage Tableを作成して、マイグレーションスクリプトを実行する。
$ bin/rails active_storage:install
Copied migration 20181015125809_create_active_storage_tables.active_storage.rb from active_storage
$ bin/rails db:migrate
Copied migration 20181015125809_create_active_storage_tables.active_storage.rb from active_storage
== 20181015125809 CreateActiveStorageTables: migrating ========================
-- create_table(:active_storage_blobs)
-> 0.0022s
-- create_table(:active_storage_attachments)
-> 0.0014s
== 20181015125809 CreateActiveStorageTables: migrated (0.0048s) ===============
- 以上で、Active Storageの準備が整った。
プロフィール画像のアップロードと表示
Memberモデルの拡張
クラスメソッドhas_one_attached、クラスメソッドattribute
- 属性
profile_picture
- Active Storageが提供するクラスメソッドhas_one_attachedを使うと、モデルオブジェクトに対して1個のファイルを添付できるようになる。
- 1個のファイルを添付するための属性をモデルクラスに追加する。
has_one_attached :profile_picture
を追加する。属性profile_picture
が追加される。
- 属性
new_profile_picture
- モデルに読み可能な属性である、
attribute :new_profile_picture
を追加する。あたかもnew_profile_picture
があるようにプログラミングできる。一時的に保存するために使用する。
- モデルに読み可能な属性である、
app/models/member.rb(一部)
class Member < ApplicationRecord
has_secure_password
has_many :entries, dependent: :destroy
has_one_attached :profile_picture
attribute :new_profile_picture
「プロフィール画像」フィールドの設置
- tableタグ内の最上位に、以下のファイルアップロード用部品を追加する。
app/views/shared/_member_form.html.erb(一部)
<tr>
<th><%= form.label :new_profile_picture %></th>
<td><%= form.file_field :new_profile_picture %></td>
</tr>
- 日本語ローケールテキストに、
new_profile_picture: プロフィール画像
を追加する。
config/locales/ja.yml(一部)
attributes:
member:
new_profile_picture: プロフィール画像
- MembersControllerのストロング・パラメーターに
:new_profile_picture
を追加する。
app/controllers/members_controller.rb(一部)
private def member_params
attrs = [
:new_profile_picture,
- AccountsControllerも同様、ストロング・パラメーターに
:new_profile_picture
を追加する。
app/controllers/accounts_controller.rb(一部)
private def account_params
params.require(:account).permit(
:new_profile_picture,
- まだアップロード機能は実装していないが、とりあえず適当な画像を選択して、更新してもエラーが出なければOK。
画像アップロード機能の実装
- モデルクラスに、以下のメソッドを追加する。これで画像アップロード機能が動くようになる。
- いきなり
profile_picture
に入れてしまうと、アップロード時に即保存されてしまうので、new_profile_picture
とprofile_picture
に分けて、バリデーションを働かせる必要がある。
app/models/member.rb(一部)
before_save do
if new_profile_picture
self.profile_picture = new_profile_picture
# self.profile_picture.attach(new_profile_picture) でも可
end
end
アップロードされた画像の表示
-
@member.profile_picture.attached?
は、プロフィール画像が添付されているかどうか。 -
.variant(resize: "128x128")
は、128x128ピクセル内で最も大きいサイズで出力する。
app/views/members/_body.html.erb(一部)
<table class="attr">
<tr>
<th>プロフィール画像</th>
<td>
<% if @member.profile_picture.attached? %>
<%= image_tag @member.profile_picture.variant(resize: "128x128") %>
<% end %>
</td>
</tr>
- 画像が保存されたことを確認。
シードデータ
-
db/seeds/development/profile.png
を置く。 - 以下を、シードデータの一番下に追記する。
db/seeds/development/members.rb(一部)
filename = "profile.png"
path = Rails.root.join(__dir__, filename)
m = Member.find_by!(number: 10)
File.open(path) do |f|
m.profile_picture.attach(io: f, filename: filename)
end
$ bin/rails db:rebuild
- ファイルが入っていることを確認。
ファイルのデータ形式に関するバリデーション
- 画像以外のファイルが登録されたとき、表示時にエラーが出るのでバリデーションを追加する。
- モデルの親クラス
ApplicationRecord
に、ALLOWED_CONTENT_TYPES
という配列の定数を追加する。
app/models/application_record.rb
class ApplicationRecord < ActiveRecord::Base
self.abstract_class = true
ALLOWED_CONTENT_TYPES = %q{
image/jpeg
image/png
image/gif
image/bmp
}
end
- 以下のように、バリデーションを追加する。
app/models/member.rb(一部)
validate if: :new_profile_picture do
if new_profile_picture.respond_to?(:content_type)
unless new_profile_picture.content_type.in?(ALLOWED_CONTENT_TYPES)
errors.add(:new_profile_picture, :invalid_image_type)
end
else
errors.add(:new_profile_picture, :invalid)
end
end
- 日本語ローケールテキストに、
new_profile_picture: プロフィール画像
を追加する。
config/locales/ja.yml(一部)
errors:
messages:
invalid_image_type: にはJPEG、PNG、GIF、BMP形式の画像を指定してください。
- バリデーションが動いたことが確認できた。
プロフィール画像の削除
添付ファイルの削除
- モデルオブジェクトに添付されたファイルを削除するには、
purge
メソッドを使う。
$ bin/rails c
irb(main):002:0> m.profile_picture.attached?
#(省略)
=> true
irb(main):003:0> m.profile_picture.purge
Disk Storage (0.4ms) Deleted file from key: GMqCoLJjozzq5KVq3jMxUffM
Disk Storage (0.6ms) Deleted files by key prefix: variants/GMqCoLJjozzq5KVq3jMxUffM/
#(省略)
=> nil
irb(main):004:0> m.profile_picture.attached?
=> false
- 削除されていることが確認した。
- モデルに画像削除のための新項目
remove_profile_picture
を追加する。 -
elsif remove_profile_picture
がtrueになったとき、self.profile_picture.purge
(削除)の処理を追加。
app/models/member.rb(一部)
has_many :entries, dependent: :destroy
has_one_attached :profile_picture
attribute :new_profile_picture
attribute :remove_profile_picture, :boolean
#(省略)
before_save do
if new_profile_picture
self.profile_picture = new_profile_picture
# self.profile_picture.attach(new_profile_picture) でも可
elsif remove_profile_picture
self.profile_picture.purge
end
end
チェックボックスの設置
- もし画像が添付されている場合は、その画像とともに削除用にチェックボックスを設置する。
app/views/shared/_member_form.html.erb(一部)
<tr>
<th><%= form.label :new_profile_picture %></th>
<td>
<%= form.file_field :new_profile_picture %>
<% if @member.profile_picture.attached? %>
<div>
<%= image_tag @member.profile_picture.variant(resize: "128x128") %>
<%= form.check_box :remove_profile_picture %>
<%= form.label :remove_profile_picture %>
</div>
<% end %>
</td>
</tr>
- ロケールテキストに、日本語でのラベル名
remove_profile_picture: 画像を削除
を追加する。
config/locales/ja.yml(一部)
attributes:
member:
new_profile_picture: プロフィール画像
remove_profile_picture: 画像を削除
-
:remove_profile_picture
のストロング・パラメータを追加する。AccountsControllerとMembersControllerに追加する。
app/controllers/accounts_controller.rb(一部)
private def account_params
params.require(:account).permit(
:new_profile_picture,
:remove_profile_picture,
:number,
:name,
:full_name,
:sex,
:birthday,
:email
)
end
app/controllers/members_controller.rb(一部)
private def member_params
attrs = [
:new_profile_picture,
:remove_profile_picture,
:number,
:name,
:full_name,
:sex,
:birthday,
:email,
:administrator
]
- 画像を削除チェックボックスをオンにして更新すると、画像が削除される。
まとめ
- 画像ファイルのアップロードは
profile_picture
、new_profile_picture
、remove_profile_picture
の3つの項目を使うことで、添付と削除が行えることがわかった。