🔴

【Rails】Active Storageを用いて、画像投稿機能を作ろう

2024/04/17に公開

はじめに:

Railsアプリケーションにファイル添付機能を持たせるためにActive Storageがある。プログラミング初学者がVScodeを用いてRails環境の構築後、Active Storageを用いて画像投稿機能を実装できることを目標とした記事となっている。

環境:

環境構築がまだの方はこちらから
https://zenn.dev/code_journey_ys/articles/c0cc5dd5372036

  • windows 11
  • Vscode 1.87.2
  • Ubuntu 22.04
  • wsl 2.1.5.0
  • ruby 3.2.3
  • rails 6.1.7

Active Storageとは

1: Active Strageをインストールする。

ターミナル
$ rails active_storage:install

以下の出力結果が得られ、マイグレーションファイルが作成されている。

ターミナル(出力結果)
$ rails active_storage:install
Copied migration 20240416145514_create_active_storage_tables.active_storage.rb from active_storage
db/migrate/YYYYMMMMDDDD_create_active_storage_tables.active_storage.rb
class CreateActiveStorageTables < ActiveRecord::Migration[5.2]
  def change
    # Use Active Record's configured type for primary and foreign keys
    primary_key_type, foreign_key_type = primary_and_foreign_key_types

    create_table :active_storage_blobs, id: primary_key_type do |t|
      t.string   :key,          null: false
      t.string   :filename,     null: false
      t.string   :content_type
      t.text     :metadata
      t.string   :service_name, null: false
      t.bigint   :byte_size,    null: false
      t.string   :checksum,     null: false
      t.datetime :created_at,   null: false

      t.index [ :key ], unique: true
    end

    create_table :active_storage_attachments, id: primary_key_type do |t|
      t.string     :name,     null: false
      t.references :record,   null: false, polymorphic: true, index: false, type: foreign_key_type
      t.references :blob,     null: false, type: foreign_key_type

      t.datetime :created_at, null: false

      t.index [ :record_type, :record_id, :name, :blob_id ], name: "index_active_storage_attachments_uniqueness", unique: true
      t.foreign_key :active_storage_blobs, column: :blob_id
    end

    create_table :active_storage_variant_records, id: primary_key_type do |t|
      t.belongs_to :blob, null: false, index: false, type: foreign_key_type
      t.string :variation_digest, null: false

      t.index %i[ blob_id variation_digest ], name: "index_active_storage_variant_records_uniqueness", unique: true
      t.foreign_key :active_storage_blobs, column: :blob_id
    end
  end

  private
    def primary_and_foreign_key_types
      config = Rails.configuration.generators
      setting = config.options[config.orm][:primary_key_type]
      primary_key_type = setting || :primary_key
      foreign_key_type = setting || :bigint
      [primary_key_type, foreign_key_type]
    end
end

2: 作成されたマイグレーションをマイグレートする。

ターミナル
$ rails db:migrate
ターミナル(出力結果)
$ rails db:migrate
Running via Spring preloader in process 288387
== 20240416145514 CreateActiveStorageTables: migrating ========================
-- create_table(:active_storage_blobs, {:id=>:primary_key})
   -> 0.0080s
-- create_table(:active_storage_attachments, {:id=>:primary_key})
   -> 0.0052s
-- create_table(:active_storage_variant_records, {:id=>:primary_key})
   -> 0.0033s
== 20240416145514 CreateActiveStorageTables: migrated (0.0177s) ===============

3: どのモデルに対して画像を使うのかを宣言する。

app/models/post.rb
class Post < ApplicationRecord
  has_many   :comments, dependent: :destroy
  belongs_to :user, dependent: :destroy
  has_one_attached :image #追加
end

4: ビューの投稿フォームを編集し、ファイルをアップロードできるようにする。

1: 新規投稿フォームに画像をアップロードできるようf.file_fieldの記述を行う。

app/view/posts/new.html.erb
<h1>Hello</h1>

<%= form_with model: @post, url: posts_path, method: :post do |f| %>
  <div>
    <%= f.label :title, "タイトル" %><br>
    <%= f.text_field :title %>
  </div>

  <div>
    <%= f.label :body, "本文" %><br>
    <%= f.text_area :body %>
  </div>
  <!-- ここから -->
  <div>
    <%= f.label :images, "画像" %><br>
    <%= f.file_field :image, accept: "image/*" %>
  </div>
 <!-- ここまで追加 -->
  <div>
    <%= f.submit "投稿" %>
  </div>
<% end %>
<%= f.file_field :image, accept: "image/*" %>の解説
<%= f.file_field :image, accept: "image/*" %>

file_fieldを用いることで、音声・動画・画像のファイルをすべて投稿できるようになる。
accept: "image/*"を用いることで、画像ファイルのみの投稿に制限できる。

2: http://localhost:3000/posts/newにアクセスし、表示を確認する。

ファイルが投稿可能となった新規投稿画面

5: ストロングパラメータでimageを受け取れるようコントローラを編集する。

app/posts_controller.rb
class PostsController < ApplicationController
  def index
    @posts = Post.all
  end
 ~~~
 ~~~
  private
    def post_params
      params.require(:post).permit(:title, :body, :image) # imageを追加
    end
end

6: ビューの投稿一覧画面で画像が表示されるようにする。

1: 投稿一覧の表示をコピーしてindex.html.erbに張り付ける。

app/views/posts/index.html.erb
<h1>Hello</h1>
<% @posts.each do |post| %>
    <%= post.title %><br>
    <%= post.body %><br>
    <% if post.image.attached? %>
      <%= image_tag post.image, size: "150x150" %><br>
    <%else%>
      <img src="http://placehold.jp/150x150"><br>
    <%end%>
<% end %>

7: 新規投稿を行い、投稿一覧に画像が表示されるかを確認する。

1: http://localhost:3000/posts/newにアクセスし、新規投稿を行う。

新規投稿画面

2: 投稿ボタンを押すまたはhttp://localhost:3000/postsにアクセスし、投稿一覧画面が表示が正しく表示されているのを確認する。

投稿一覧画面

まとめ

・ファイル投稿機能を用いる場合は、Active Storageを用いる。
rails active_storage:installでインストール後、該当するモデルにhas_one_attached :imageを記載し、ビューとコントローラも編集する。
・複数のファイル投稿機能を用いたい場合は、複数形にする。

参考サイト

https://qiita.com/hmmrjn/items/7cc5e5348755c517458a
https://railsdoc.com/rails_base
https://railsguides.jp/v7.1/getting_started.html

おわりに

Railsアプリケーションにファイル添付機能を持たせるために必要なActive Storageについて学んだ。画像投稿機能を実装できることで、Instagramのような投稿機能を持ったアプリケーションを作成できるようになる。

Discussion