【RailsAPI】Active Storageをでファイルを保存する!

6 min read読了の目安(約5500字

前書き

先日、業務でRailsAPIActive 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.rbconfig/environments/production.rbに下記のようなコードがデフォルトであると思います。

config.active_storage.service = :local

この:localconfig/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

基本的な使い方に関しては以上です。あとはドキュメントを読み込んでいくとさらに知識がつくかなと思います。

ではでは💪