updated on 2019-07-11
今までは画像やファイルを保存したいときは、paperclipを使っていましたが、rails5.2からはactive storageが推奨されている様です。
そして腰抜かすくらい簡単に
導入できてしまいます
早速やっていきます!!
1. active_storageのインストール
$ rails active_storage:install $ rails db:migrate
active_storageの設定ファイルをインストールした後、マイグレーションを実行することでactive_storage_blobs
とactive_storage_attachments
という名前のテーブルが2つ生成されます。
Blob
はファイル名、ファイルの種類、バイト数、誤り検出符号などのメタデータを保持するモデルで、Attachment
モデルは、BlobオブジェクトとActive Recordオブジェクトを紐付けるための中
テーブルですが、全くいじる必要のないモデルなので、特に覚えなくても結構です。
2. model生成
$ rails g model Article title:string body: text $ rails db:migrate
3. 実装
article.rb
# article.rb class Article < ApplicationRecord has_one_attached :image end
:image
はファイルの呼び名で、:photo
、:avatar
、:profile
など、好きなものを指定してください。
ここで指定した image は、articlesテーブルのカラムの様な扱いになりますが、imageテーブルなどを作る必要はないです。Active Storageは裏側でBlob
とAttachment
モデルを使って、勝手に
article.image
を使えるようにしてくれます。
articles_controller.rb
class CommentsController < ApplicationController before_action :find_article, only: [:edit, :update, :show, :destroy] def new @article = Article.new end def create @article = Article.new(article_params) if @article.save flash[:notice] = "保存しました" redirect_to article_path(@article) else flash[:alert] = "エラーが発生しました" render :new end end def show end def edit end def update if @article.update(article_params) flash[:notice] = "更新しました" redirect_to article_path(@article) else flash[:alert] = "エラーが発生しました" render :edit end end def destroy if @article.destroy flash[:notice] = "削除しました" redirect_to articles_path else flash[:alert] = "エラーが発生しました" end end # imageは、titleフィールドやbodyフィールドと同じ様に、articlesテーブルのカラムの様な扱いをする private def article_params params.require(:article).permit(:title, :body, :image) end def find_article @article = Article.find(params[:id]) end end
articles/_form.html.erb
<%= form_with model: article, local: true do |f| %> <% if @article.errors.any? %> <div id="error_explanation"> <h2><%= "#{pluralize(@article.errors.count, "error")} により保存できませんでした" %></h2> <ul> <% @article.errors.full_messages.each do |msg| %> <li><%= msg %></li> <% end %> </ul> </div> <% end %> <%= f.text_area :title %><br> <%= f.file_field :image %><br> <%= f.text_area :body %><br> <%= f.submit %> <% end %>
new.html.erb
<h2>新規投稿</h2> <%= render "articles/form", artilce:@article %>
edit.html.erb
<h2>編集</h2> <%= render "articles/form", artilce:@article %>
show.html.erb
<div class="col-sm-11 col-sm-offset-1 col-xs-12"> <h2 class="text-center"><%= @article.title %></h2> <div class="text-center"> <% if @article.image.attached? %> <%= image_tag @article.image, :alt => "イメージ", width: '30%', height: '30%' %> <% end %> </div> <h5 class="text-center"><%= @article.created_at.strftime('%b %d, %Y') %></h5> <div class="fr-view"> <%= raw @article.body %> </div> </div>
<% if @article.image.attached? %>
<%= image_tag @article.image, :alt => "イメージ", width: '30%', height: '30%' %>
<% end %>
の部分の :alt => "イメージ", width: '30%', height: '30%'は好きに変えてください。
これでactive_storageへの投稿、更新、削除が完成しました
しかし...active_storageは複数のファイルを保存することもできますので、そちらも紹介します。
article.rb
# article.rb class Article < ApplicationRecord # has_one_attached :image has_many_attached :images end
articles_controller.rb
class CommentsController < ApplicationController before_action :find_article, only: [:edit, :update, :show, :destroy] def new @article = Article.new end def create @article = Article.new(article_params) if @article.save flash[:notice] = "保存しました" redirect_to article_path(@article) else flash[:alert] = "エラーが発生しました" render :new end end def show end def edit end def update if @article.update(article_params) flash[:notice] = "更新しました" redirect_to article_path(@article) else flash[:alert] = "エラーが発生しました" render :edit end end def destroy if @article.destroy flash[:notice] = "削除しました" redirect_to articles_path else flash[:alert] = "エラーが発生しました" end end # imageは、titleフィールドやbodyフィールドと同じ様に、articlesテーブルのカラムの様な扱いをする private def article_params # params.require(:article).permit(:title, :body, :image) params.require(:article).permit(:title, :body, :images) end def find_article @article = Article.find(params[:id]) end end
articles/_form.html.erb
<%= form_with model: article, local: true do |f| %> <% if @article.errors.any? %> <div id="error_explanation"> <h2><%= "#{pluralize(@article.errors.count, "error")} により保存できませんでした" %></h2> <ul> <% @article.errors.full_messages.each do |msg| %> <li><%= msg %></li> <% end %> </ul> </div> <% end %> <%= f.text_area :title %><br> <!-- <%= f.file_field :image %><br> --> <%= f.file_field :images, multiple: true %><br> <%= f.text_area :body %><br> <%= f.submit %> <% end %>
show.html.erb
<div class="col-sm-11 col-sm-offset-1 col-xs-12"> <h2 class="text-center"><%= @article.title %></h2> <div class="text-center"> <!-- <% if @article.image.attached? %> <%= image_tag @article.image, :alt => "イメージ", width: '30%', height: '30%' %> <% end %> --> <% if @article.images.attached? %> <% @article.images.each do |image| %> <%= image_tag image %> <br> <% end %> <% end %> </div> <h5 class="text-center"><%= @article.created_at.strftime('%b %d, %Y') %></h5> <div class="fr-view"> <%= raw @article.body %> </div> </div>
new.html.erb(変更なし)
<h2>新規投稿</h2> <%= render "articles/form", artilce:@article %>
edit.html.erb(変更なし)
<h2>編集</h2> <%= render "articles/form", artilce:@article %>
THAT'S ALL RIGHT!!
ちなみに、今回は使わなかったものの、urlを生成したりプレビュー、ダウンロードリンクをするときは以下を使用
<%= link_to 'プレビュー', rails_blob_path(article.image, disposition: 'preview') %>
<%= link_to 'ダウンロード', rails_blob_path(article.image, disposition: "preview") %>
例) Rails.application.routes.url_helpers.url_for(Article.find(145).image) * url_for も rails_blob_path と同じ!
config/environments/development.rb
# ...
# Store uploaded files on the local file system (see config/storage.yml for options)
config.active_storage.service = :local
# ...
config/environments/production.rb
# ...
# Store uploaded files on the local file system (see config/storage.yml for options)
config.active_storage.service = :local
# ...
defaultの local
とは、 config/storage.yml
で定義された保存先の名前
config.active_storage.service = :local
を :amazon
, :google, :microsoft
のいづれかと置き換えて、config/storage.yml
の方に、必要な認証情報などの値を入力します。
config/storage.yml
test: service: Disk root: <%= Rails.root.join("tmp/storage") %> local: service: Disk root: <%= Rails.root.join("storage") %> # Use rails credentials:edit to set the AWS secrets (as aws:access_key_id|secret_access_key) # amazon: # service: S3 # access_key_id: <%= Rails.application.credentials.dig(:aws, :access_key_id) %> # secret_access_key: <%= Rails.application.credentials.dig(:aws, :secret_access_key) %> # region: us-east-1 # bucket: your_own_bucket # Remember not to checkin your GCS keyfile to a repository # google: # service: GCS # project: your_project # credentials: <%= Rails.root.join("path/to/gcs.keyfile") %> # bucket: your_own_bucket # Use rails credentials:edit to set the Azure Storage secret (as azure_storage:storage_access_key) # microsoft: # service: AzureStorage # storage_account_name: your_account_name # storage_access_key: <%= Rails.application.credentials.dig(:azure_storage, :storage_access_key) %> # container: your_container_name
defaultの保存先の local
は、使用するサービスが Disk
(ローカルディスク)に設定れていて、保存先がrailsアプリ直下の/storage
ディレクトリに指定されています。
保存先に応じてコメントを解除してください。
amazon: を使用するあなたは gem aws-sdk-s3
goolge: を使用するあなたは gem google-cloud-storage
microsoft: を使用するあなたは gem azure-storage
をGemfileに追記
なお、アクセスキーなどの機密情報は、Rails Credentials(暗号化して保存するためのRails新機能)を使って入力!!
$ EDITOR=vim rails credentials:edit
i を押す
実際の値を入れていく
escを押す
ZZ を押す
保存完了
(入力した内容はconfig/master.key
を用いて暗号化され、config/credentials.yml.enc
が生成されます)
$ rails credentials:show
で確認できる
gem "aws-sdk-s3", require: false
$ bundle install
と叩きます。
config/environments/production.rb
# ファイル保存先を:localから:amazonに変更 config.active_storage.service = :amazon
config/environments/development.rb
# 開発環境(development)でAmazon S3の動作を確認したい場合はこちらの方も変更しましょう config.active_storage.service = :amazon
config/storage.yml
# 以下の部分をコメント解除する amazon: service: S3 access_key_id: <%= Rails.application.credentials.dig(:aws, :access_key_id) %> secret_access_key: <%= Rails.application.credentials.dig(:aws, :secret_access_key) %> region: ap-northeast-1 # これは日本の地域コード bucket: my_bucket_name # 自分で作成したS3のバケットの名前
$ EDITOR=vim rails credentials:edit
(エディタはVim(vim)かAtom(atom)かVSCode(code)かSublimeText(subl))
aws: access_key_id: 123 #ここに自分のアクセスキーIDをコピペ secret_access_key: 456 #ここに自分のシークレットアクセスキーをコピペ
Vim: i
で入力開始、esc
→ ZZ
で終了
$ rails credentials:show
で内容を確認できる
以上でs3にアップロードされるようになりました。s3がこんなに簡単に使えてしまうことが驚き栗の木超ラッキーです!
Credentialsを使用する場合
config/credentials.yml.enc
の中身を復号化するために必要なconfig/master.key
ファイルを本番環境にも配置する必要があります。しかし、master.key
はセキュリティ上, .gitignore されてあり、Gitリポジトリをそのままデプロイする本番環境(Herokuなど)の場合は、master.key
の中身をコピーして、環境変数 RAILS_MASTER_KEY
としてセットしなければいけません。ちなみに、Herokuをお使いの場合は $ heroku config:set RAILS_MASTER_KEY=123
で環境変数を用意できます。
参考文献 こちらの方