タイトル通り、ActiveStorageを使用してseedファイルへ画像の追加を行っていきます。
記事を書いている私の状況としては
ECサイトをbootstrapのテンプレートを使用して開発中。
データベースへ反映(追加)したデータをrailsのviewで確認が取れるまで行えました。
環境
Dockerで作成したコンテナの内部でRailsを動かしていきます。
基本的にコンテナ内部でrails cを使用してデータの中身を確認しつつ進めていきます。
細分化して考える
ペアプロしていただいたHCメンバーの方から「何事も細かく切り分けて行う」癖をついてた方がいいとアドバイスをいただきました。
特に初めて触るorあまりよくわかっていないもので「〇〇をする」というのはハードルが高い。
高いハードルはまずは細かく切り分けてアプローチのかけ方を変えた方が実践的かつ良質な経験値と時間を得られることを教えていただきました。
画像の表示に係るプロセス
今回は「画像を表示させる」のがゴールです。
そこで、漠然としてしまっている途中のプロセスを明確にして作業を進めます。
- 画像を用意する
- 用意した画像をapp/assets/images へ入れる
- seedへ反映する方法を調べ実践
- 反映したデータがrails cでも確認できるか(データの確認)
- 確認したデータを変数などへ代入し、確認
- 変数へ代入できることがわかれば、viewsのhtml等でインスタンス変数へ渡したものを表示
ざっくりと画像表示に係るプロセスを明記するとこのようになりました。
細かくしてできるところからやる
学習の段階でインプットができればアウトプットが重要。
実際、私も手を動かす(アウトプット)と読む(インプット)ではアウトプットを行った方が知識の定着率も高いように感じます。
ただハードルにぶち当たったとき、忽然と手が止まります。
そういった時は「細かく」して何がまずできるかを考え「手を動かす」必要があるそうです。
「画像を表示する」では「画像を用意する」「画像を特定の場所へ保存」などは比較的簡単なのですぐにできます。
テーブルのカラム
今回画像を表示させたいのは商品一覧という画面の各商品。
それぞれに対して画像を表示していきます。
商品モデル(Items)のテーブルカラムはこんな感じ
t.string :name
t.integer :price
t.string :description
t.string :item_image
item_imageのカラムを作成していますが、今作成しているデータではitem_imageにはnilを入れています、
[#<Item:0x00007f58b023dab0
id: 1,
name: "爆煙mods",
price: 1000,
description: "爆煙タイプのmodです",
item_image: nil>,
#<Item:0x00007f58aee0d860
id: 3,
name: "MTL mods",
price: 1500,
description: "MTLタイプで喫煙者向け",
item_image: nil>,
#<Item:0x00007f58aee0d7c0
実際に作成したデータを確認してもitem_imageはカラムはあるがnilのままです。
ここにデータを追加していきます。
ActiveStorageをセットアップする
色々な方の記事を参考にする前に
まずは公式のリファレンスを読みます。
https://railsguides.jp/active_storage_overview.html#セットアップ
公式リファレンスが正解であって、個人の記事が正解とは限らないからです。
config/storage.ymlの内容を変更して反映
公式リファレンスに書かれている内容に沿って色々と変更を行います。
test:
service: Disk
root: <%= Rails.root.join("tmp/storage") %>
local:
service: Disk
root: <%= Rails.root.join("storage") %>
config/strage.ymlの内容を変更し、ローカルのDiskサービスをdevelopment環境で使用するのためconfig/environments/development.rbに下記を追記
config.active_storage.service = :local
他にもamazon s3などをstorage.ymlに明記する必要があるようですが、
とりあえずlocalへ保存した内容がlocalhostへ接続し、確認できれば良いものとします。
has_one_attachedでファイルをレコードに添付する
Itemモデルの中にhas_one_attachedを明記.
下にあるものは画像のサイズを変更するもの。
class Item < ApplicationRecord
#1対1で関連つける宣言
has_one_attached :item_image do |attachable|
attachable.variant :thumb,resize_to_limit: [450,300]
end
end
Rails6以降はジェネレーターコマンドが使えるようなので下記コマンドを実行します
モデルなどをまだ用意してない場合は下記を実行
用意したあとに行うとマイグレーションファイルなどが上書きされるので、あくまでまだモデルを作っていないときにこれは行うとよし。
モデルがあるなら無視してOK
bin/rails g model Item item_image:attachment
invoke active_record
The name 'Item' is either already used in your application or reserved by Ruby on Rails. Please choose an alternative or use --skip-collision-check or --force to skip this check and run this generator again.
何やらエラーがでてきました。
https://qiita.com/W2020T/items/ceda904fb96dbd74ae59
こちらの記事が参考になりまして、
今回のエラーは「すでにItemモデル作ってるぞ?」
というものでした。
記事を参考にモデルを削除してやり直すのでもいいかもしれませんが、オプションを使ってできないか試してみます。
bin/rails g model にオプションを追加して実行してみる
ターミナルに書かれているオプションが何かを調べてみると
オプション | 意味合い | 何をする |
---|---|---|
—skip-collision-check | コリジョンチェックを無視する | コリジョン(衝突)を無視するためのオプション |
—force | ファイルが存在する場合は上書き | すでに作成しているものに対して上書きする |
それぞれオプションの意味が違うことがわかります。
Itemモデルはそのままで上書きしたいので—forceオプションを付け加えて再度実行します。
invoke active_record
remove db/migrate/20230905144232_create_items.rb
create db/migrate/20230927122735_create_items.rb
identical app/models/item.rb
invoke rspec
identical spec/models/item_spec.rb
root@29c036ad08a3:/myapp#
無事に実行できたようです。
マイグレーションファイルは作り直されたものの、Itemモデルに変更は加えられていません。
「 identical」は「一致」という意味があるので、変わりなしと判断しました。
一度roolbackして変更を加える
まっさらになってしまったitemモデルのマイグレーションファイルに変更を加えて元のあった状態へ戻しました。
ジェネレートコマンドを実行しても上書きされるものは少ない。
必要だったカラムの設定などがあった時はrollbackしてマイグレーションファイルに書いていたカラムなどの設定を変更してマイグレーションを実行する。
seedファイルへ変更を加える
画像はなんでもいいので用意します。
今回は8つ商品を追加するのでそれぞれ違った画像を表示する必要がありました。
8つ画像を用意した後、
apps/assets/images/ の中に格納。
それぞれをseedファイルへ初期値として登録するのが今回の目的。
seedファイルで商品を追加します。
item1 = Item.create!(
name: "テスト商品1",
price: 1250,
description: "これはテスト商品1についての説明です",
)
item1.item_image.attach(io: File.open(Rails.root.join('app/assets/images/image.jpg')),filename: 'image.jpg')
item1.save!
同時に複数のデータを作る方法もありますが、
今回はそれぞれ違ったデータにしておきたかったのもあり、item1~item8まで作成しました。
表示の確認を行う
これで初期値は登録できたので表示の確認を行います。
それぞれ別々の画像の表示ができました。
localhost:3000 へアクセスすることで画像が表示されましたが、先送りにしていたのでherokuでは表示ができておりません。
こちらは追加で変更を加える必要があります。
そちらについては別の記事でまとめようと思います。