【RailsAPI】Active Storageをでファイルを保存する!
前書き
先日、業務でRailsAPI
でActive Storage
を使う機会がありました。忘備録として、導入~設定方法~実装を解説したいと思います。
RailsAPI
の環境構築はこちらの記事から。
Active Storage
とは
Rails
にデフォルトで備わっている機能の一つです。ドキュメントによると下記のように説明されています。
Active StorageとはAmazon S3、Google Cloud Storage、Microsoft Azure Storageなどの クラウドストレージサービスへのファイルのアップロードや、ファイルをActive Recordオブジェクトにアタッチする機能を提供します。
まとめると下記のようなイメージです。
-
Active Record
オブジェクトにファイルデータをアタッチできる AWS
,GCP
,Azure
などのクラウドストレージサービスに手軽に保存できる
手軽にファイルデータを扱うのに必要な機能を提供してくれる、という感じでしょうか。
実際にActive Storage
を使ってみる
では、以降からコード+文章で解説していきます!!
Active Storageの設定
【1】DB周りの設定
rails active_storage:install
このコマンドを実行すると2つのテーブルを作成するためのマイグレーションファイルが作成されます。
-
active_storage_blobs
テーブル -
active_storage_attachments
テーブル
内容としては下記の通り。(ちょっと変えているところがあります。)
active_storage_attachments
create_table :active_storage_attachments do |t|
t.string :name, null: false
t.references :record, null: false, polymorphic: true, index: false
t.references :blob, null: false
t.datetime :created_at, null: false
t.index [ :record_type, :record_id, :name, :blob_id ], name: "index_active_storage_attachments_uniqueness", unique: true
t.string :active_storage_blob_id, column: :blob_id
end
active_storage_blobs
create_table :active_storage_blobs do |t|
t.string :key, null: false
t.string :filename, null: false
t.string :content_type
t.text :metadata
t.bigint :byte_size, null: false
t.string :checksum, null: false
t.datetime :created_at, null: false
t.index [ :key ], unique: true
end
確認したら、下記のコマンドを実行してマイグレートしてください。
rails db:migrate
【2】保存先の設定をする。
config/environments/development.rb
とconfig/environments/production.rb
に下記のようなコードがデフォルトであると思います。
config.active_storage.service = :local
この:local
は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
# mirror:
# service: Mirror
# primary: local
# mirrors: [ amazon, google, microsoft ]
このlocal
の部分にどこに保存されるか定義されています。デフォルトでは、Disk
に保存されるようになっていますね。ちなみに、S3
などのクラウドストレージサービスに保存させる場合には、このconfig/storage.yml
に諸々の設定を書き込めばOKです。
設定は以上です。次から実際の使い方について見ていきます!
Active Storageを実際に使ってみる
基本的な使い方は下記のような感じです。
class Post < ApplicationRecord
has_one_attached :image
end
上記のようにモデル層に、ファイル情報をアタッチすることでPostモデルがファイル情報を持っているように挙動してくれます。
コントローラ側では以下のような感じです。
class PostsController < ApplicationController
def create
post = Post.new(post_params)
if post.save
render json: post
else
render json: post.errors, status: 422
end
end
def post_params
params.permit(:name, :image)
end
end
post
モデルがimage
カラムを持っているように動いてくれていますね。
基本的な使い方は以上です。次からActive Storage
の詳細な機能について解説していきます。
保存済みのファイルのURLを返す
最初に設定としてconfig/environments/development.rb
にコードを追加します。
Rails.application.configure do
...
# 下記のコードを追加
Rails.application.routes.default_url_options[:host] = 'localhost'
Rails.application.routes.default_url_options[:port] = 3000
end
そして、該当するモデルで下記のようにしてください。
class Post < ApplicationRecord
# ここから
include Rails.application.routes.url_helpers
# ここまでを追加してください。
has_one_attached :image
# ここから
def image_url
image.attached? ? url_for(image) : nil
end
# ここまで追加してください。
end
-
url_for
メソッドを使うためにRails.application.routes.url_helpers
をincludeしてください。 -
image_url
メソッドでは、画像のURLを返しています。
ちなみに
url_for(image)
の部分について少し補足しておきます。
アクセスした時には、実際のサービスエンドポイントへのリダイレクトが返されます。**なので公開されるURLと実際のURLを切り離すことができます。**すごく便利ですね。
準備はこれで完了です。コントローラでは以下のように書けば、URLを出力することできます。
class PostsController < ApplicationController
# 下記のアクションを追加
def index
render json: Post.all, methods: [:image_url]
end
def create
post = Post.new(post_params)
if post.save
render json: post
else
render json: post.errors, status: 422
end
end
def post_params
params.permit(:name, :image)
end
end
methods: [:image_url]
の部分で、メソッドの結果をjson
で出力することができます。(実際には、こんな感じには書かずに僕だったらシリアライザーで整形します。)
URLに関しては以上です。
複数のファイルをアタッチしたい
この場合はモデルでhas_many_attached
のように宣言してあげれば、複数のファイルをアタッチすることができます。実際には下記のようなイメージです。
class Post < ApplicationRecord
include Rails.application.routes.url_helpers
has_many_attached :images
def image_url
image.attached? ? url_for(image) : nil
end
end
基本的な使い方に関しては以上です。あとはドキュメントを読み込んでいくとさらに知識がつくかなと思います。
ではでは💪