0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

#3 Rails × Vue.jsで動的なページをSPAさせる

Last updated at Posted at 2021-08-08

前回の続き

railsからjsonデータをVue.jsの方に受け渡すことができたが、画像のデータがうまいことVue.jsのほうに渡っていないきがするのですね。

app/javascript/app.vue
のほうに{{dirnk.image}}
とやると、

"name": "image", "record": { "id": 10, "name": "ddd", "price": 3000, "explain": "dddddd", "user_id": 7, "created_at": "2021-08-06T06:50:21.611Z", "updated_at": "2021-08-06T06:50:21.649Z", "region_id": 1, "body_id": 1, "acidity_id": 1, "processing_id": 1, "likes_count": null } }

このようなjsonデータがviewに表示される。

考えられる原因第1

users_controller.rb


class Api::UsersController < ApplicationController
  def show
    @user = User.find(params[:id])
    @drinks = @user.drinks.order('created_at DESC').includes(image_attachment: :blob)
  end
end

drinksの方はあくまでユーザークラスのインスタンスなので、drink.image
とやってもうまくいかない説がある。

考えられる原因第2

.erbで<%= image_tag @drink.image%>

とやるように、
vueのほうにも画像を表示させるメソッドがあるかも

考えられる原因第3

画像データをvueの方に渡すときに、jsonの特別な書き方がある。

https://qiita.com/youichiro/items/2987cd9b4ab29691eb77
このきじを参考に色々みていきたい

考えられる原因第4

俺にはまだ早い説
だとしたら、画像はrailsのactive storageに処理を任せて、
テキスト情報だけは vueの方で書くしかない。。。

考えられる原因第1

にまずはアプローチ。そもそもrailsのほうでは、@drink.imageとやって上手く言ってるのか確かめていきます

views/users/show.html.erb


<% @drinks.each do |drink| %>
<%= image_tag drink.image%>
<% end %>

にこんな感じでやればうまくいきました。

drink.imageでやればうまくいくので、
jsonで上手く画像データをvueに受け渡せているなら、vueの方でもimage_tag的な画像を表示させるメソッドを使えばdrink.imageでも上手くいきそうですね。

ちなみにvueのほうには、

app/views/api/users/show.json.jbuilder

show.json.jbuilder
json.array! @drinks, :id ,:name , :price , :explain ,
                     :image , :region_id , :body_id , 
                     :acidity_id , :processing_id ,
                     :likes_count , :user_id

こんな感じでデータをvueに受け渡しています。

drink.nameとかではしっかりとvueのほうに表示させれるので、問題ないでしょう。

このような書き方でvueに画像データを受け渡せているか微妙なのですが、一旦受けわたせている前提で、
考えて、vueの方でrailsのimage_tag的なメソッドを探すってことで

考えられる原因第2

rails vue 画像データ jsonでしらべたらどうやら、

json.array! @drinks, :id ,:name , :price , :explain ,
:image , :region_id , :body_id ,
:acidity_id , :processing_id ,
:likes_count , :user_id
こういった形式では、画像データを送れないっぽいので、そもそも画像データをvueに渡せてない。
ってことでこの線は一旦消える。
受け渡せることができたら、またこの原因に戻ろう。

考えられる原因第3

ってことでrailsの画像データをvueの方に受け渡す処理をかいていこうとおもいます。

https://qiita.com/terufumi1122/items/bdc96617c818dac01b6d
https://qiita.com/ozin/items/5ec81a4b126b8ebf7a96
https://qiita.com/tabakazu/items/5489632c534c56db6a4d
https://qiita.com/youichiro/items/2987cd9b4ab29691eb77

色々ヒットしたので
これかの記事を参考にして頑張る

まずは、https://qiita.com/youichiro/items/2987cd9b4ab29691eb77
これから
微妙に自分がやりたい形式でなかった。jbuilderを使わずやっていたので、自分の理解では飲み込めなかった。

次は、https://qiita.com/terufumi1122/items/bdc96617c818dac01b6d
この方の記事。
まさしく自分がやりたいことがタイトルになっているので、なんかいけそう

その前に、https://qiita.com/tabakazu/items/5489632c534c56db6a4d
こっちを済ませとく必要がある。今さっきやろうとしてた記事にeyecatchメソッドがあって、それを先に定義していかなければならない。。。。

models/drink.rb

    def image=(image)
      if image.present?
        prefix = image[/(image|application)(\/.*)(?=\;)/]
        type = prefix.sub(/(image|application)(\/)/, '')
        data = Base64.decode64(image.sub(/data:#{prefix};base64,/, ''))
        filename = "#{Time.zone.now.strftime('%Y%m%d%H%M%S%L')}.#{type}"
        File.open("#{Rails.root}/tmp/#{filename}", 'wb') do |f|
          f.write(data)
        end
        image.detach if image.attached?
        image.attach(io: File.open("#{Rails.root}/tmp/#{filename}"), filename: filename)
        FileUtils.rm("#{Rails.root}/tmp/#{filename}")
      end
    end

うん、意味がわからんので、頑張って一つずつ解説します。

まず、image=(image)、このメソッドの定義の仕方。。。
どっかで見たことあるけど、image(image)との違いがよくわからんくなった。
https://donghai821.hatenadiary.org/entry/20080406/1207479842
def hoge=(fuga)は書き込みオンリーらしい。
このようなメソッドを「要素代入関数」と言うらしい。へぇーー。

https://wa3.i-3-i.info/diff397data.html
エンコードとデコードの違いはこれ。

なぜbase64をつかうの??
かつての電子メールを送るためのプロトコルSMTPでは、ASCIIといわれる7bitで表現される英数字しか送ることができませんでした
したがって、メールを使って画像や音声などのデータをやりとりしたいと思った時に、英数字しか対応していないSMTPでは、それらのデータを送受信することができませんでした

そこで、すべてのデータを英数字で表すMIME(Multipurpose Internet Mail Extensions)という規格が登場し、その中でbase64というデータの変換方法が定められました
これによって、受信側と送信側がMIMEに則ってエンコード・デコードをすることで、メールを通して画像や音声などの送受信が可能になりました

現在では、JSONなどで特殊文字を含まないように画像データをbase64でエンコードしたり、Webページの表示の際にリクエスト数を減らすためにbase64でエンコードした画像をhtmlにそのまま埋め込むなどの用途で用いられています

そこで、たしかに画像データを文字列に置き換えて送受信をしたいから、画像をエンコードする必要があるのかもね。

drink.rb

  # Base64形式でうけとったimageデータをエンコードし、
  # 一時的にtmp配下に画像ファイルを作成、作成した画像ファイルをアタッチ
  # その後画像ファイルを削除
    def image=(image)
      if image.present?
        # もし、imageがあったら?
        prefix = image[/(image|application)(\/.*)(?=\;)/]
        # ???
        type = prefix.sub(/(image|application)(\/)/, '')
        # この正規表現にマッチしたものを空文字にする
        data = Base64.decode64(image.sub(/data:#{prefix};base64,/, ''))
        # 画像のデータをこの文字列にマッチしたものは、空にして,
        # 残った文字列をデコード
        filename = "#{Time.zone.now.strftime('%Y%m%d%H%M%S%L')}.#{type}"
        # 画像のファイルネームを定義
        File.open("#{Rails.root}/tmp/#{filename}", 'wb') do |f|
          f.write(data)
          # ファイルにデータを書き込み
        end
        image.detach if image.attached?
        image.attach(io: File.open("#{Rails.root}/tmp/#{filename}"), filename: filename)
        FileUtils.rm("#{Rails.root}/tmp/#{filename}")
      end
    end

正直この程度しか分からんかった。
なんでこれらのコードを実行する必要があるのかがよくわからんかった。。
後でrailsの画像周りの知識をしっかり勉強しよう。
https://railsguides.jp/active_storage_overview.html
ホントはダメだけど、理解しないまま一旦実装してしまおう。
一旦全体の動き把握して、実装してから理解する。
まさに駆け出しって感じですね。。精進します。。。

https://qiita.com/terufumi1122/items/bdc96617c818dac01b6d
この記事には、

posts_controller.rb
  def show
    post = Post.find(params[:id]).as_json #JSON形式にしておく

    eyecatch = post.eyecatch #eyecatchは添付した画像ファイル

    if eyecatch.present?
      post['image'] = encode_base64(eyecatch) # 画像ファイルを1.で定義したメソッドでBase64エンコードし、renderするデータに追加する
    end

    render json: post
  end

と書いてある。。。

自分の場合は、

user_controller.rb

  def show
    @user = User.find(params[:id])
    @drinks = @user.drinks.order('created_at DESC').includes(image_attachment: :blob)
    
  end

何がやっかいかと言うと、
こっちは投稿(drink)を複数取得して、配列だから、
配列一つ一つに対して処理をしていかないといけない。。。
eachとか使えるけど、それでうまくいくのだろうか。。。

配列だと扱いが難しいから、まずは画像一枚一枚を非同期的に表示させていく。

つまり、 @drinks = @user.drinks.order('created_at DESC').includes(image_attachment: :blob)

これだと複数枚画像があるけど、

drinks#showだったら、一枚しか画像がないから、それをうまいこと表示させていきたい

ってことで、drinks#showのSPA化を一旦目指す。

配列データのSPA化は一応できたけど、画像の扱いが今は難しかったから、
一旦単一データのSPA化をしてみたいと思う。
ってことでブランチを一旦削除、、、ピエン

画像が入ってる配列データは俺には早かったっていう
考えられる原因第4に当てはまってしまった!リベンジかますで!!!

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?