こんにちはRyujiです。
Active::Storageめっちゃ便利ですよね!圧倒的に少ないコードで画像表示を実装することができました。
ただし、新機能なだけに文献が少ない!今回は詰まった非同期での画像表示について書きます。
Contents
今回やりたいこと
Rails 5.2でajaxで送られてきたリクエストに対して、Active::storageの画像付きデータをjbuilderで返送して、クライアントで表示したい。
Active::Storageとは?
そもそもActive::Storageって何ですか?って人
Active::StorageはRails 5.2から使用できるようになった、画像アップロードできる機能です。railsに標準付属である上に、非常に簡単に実装できます。
他の実装方法としては、carrierwaveなどが挙げられます。
Active::Storageの基本的な使い方
基本的にRails guideがとてもわかりやすいです。
https://railsguides.jp/active_storage_overview.html
諸々設定した後、アソシエーションのようにattachして、
class Item < ApplicationRecord
has_many_attached :images # 複数画像の場合
end
def create
@item = Item.new(item_params)
end
private
def item_params
params.permit(:name, :price, images: []) # 複数画像の場合
end
Viewで呼び出すだけ!
= image_tag @item.images[0]
jbuilderでActive::Storageの画像を渡す
今回は非同期で表示したいので、先ほどの
= image_tag @item.images[0]
みたいな書き方は使えません。
その為、以下のような実装方法になるかと思います。
ajaxで通信します。
$.ajax({
method: "GET",
url: "./test",
dataType: "json",
}).done(function(data){
data["items"].forEach(function(item){
$(".main_block__item").append(item.image)
});
})
コントローラの設定はこんな感じ
def test
@items = Item.all
respond_to do |format|
format.json {}
end
end
そしてjbuilderの設定
json.set! :items do
json.array! @items do |item|
json.id item.id
json.name item.name
json.price item.price
json.image item.images[0]
end
end
とりあえず画像一枚jbuilderで送信します。
これじゃダメなんです!!
実は item.images[0] で出力されるurlと、
通常のrubyで出力する方法= image_tag @item.images[0]で出力されるurlは
異なります。
Active::Storageとimage_tagがうまいこと裏でやってくれているんですよね。
= image_tag @item.images[0]で出力されるurl
<img src="http://localhost:3000/rails/active_storage/blobs/eyJfcmFpbHMiOnsibWVzc2FnZSI6IkJBaHBldz09IiwiZXhwIjpudWxsLCJwdXIiOiJibG9iX2lkIn19--8379cabd9a6ac222ffa18e561d4eb900110fe265/-E3-82-B9-E3-82-AF-E3-83-AA-E3-83-BC-E3-83-B3-E3-82-B7-E3-83-A7-E3-83-83-E3-83-88-202019-07-12-2011.39.07.png">
こんなのを動的に作り出さなければなりません。
url_forを使用して画像を表示する
いや動的に複雑なurlを同じように生成するのって困難ですよね!
そんなあなたに救世主がいました。url_forです。
使い方は簡単です。
jbuilderを書き直します。
json.set! :items do
json.array! @items do |item|
json.id item.id
json.name item.name
json.price item.price
json.image url_for(item.images[0])
end
end
url_forは実は、Rails Guideの5.添付ファイルへのリンクに説明されていました。
(Rails Guide読んでも、最初はこんな使い方できるって気づかなかったよ、、、)
url_forを使うと5分間有効な永続リンクが作成されるんですよね。それでjavascriptでも操作して表示することが可能になります。
副産物として、一回表示した画像は早く表示できるようになりました!
まとめ
非同期で画像表示するときはurl_forを使いましょう。
他の方法があるなら教えて欲しいです!
Active::Storageは超便利・超簡単ですけど、割と新機能だから文献が少ないのが難しいところでした。