アラフォーがお金持ちになるためエンジニア目指すブログ

お金も根性も学歴もないアラフォーまきのがエンジニアになってお金持ち目指すよ!

【Railsメモ】RailsのJSに渡すcreated_atをいい感じで表示したい+α

どうも、アラフォーまきのです。



実は今作っている卒業制作のアプリで、
Twitterみたいに、なんらかの投稿があったら、
それを最新の投稿がトップに来るように表示したくなったよ!



動的な表現なので、JSが必要らしい。
教わりながらとりあえずそれらしいものはできたよ!



でも、created_atでいつの投稿か?をかっこよく表示するやり方が
よくわからなくて、メンターさんに教わったのでメモするよ!



超簡単だから!



(土台ができていれば)たった3つの作業でできちゃうから!
でもまず土台のところで+αあって、かなり情報量多いよあはは!


環境

・Rails 5.2.1

・JavaScript ES6(多分)

・jQuery 3x(多分)

現在の状態(土台)


【routes.rb】

get '/ajax/justnow' => 'mokus#justnow'


画面はそのままで、一定時間ごとに情報をロードすることで
TLを表現するよ!




ということでAjax先生に出張ってもらうので、
Ajaxによるリクエストにお応えするroutesを設定したよ!



【mokus_controller】

def justnow
    mokus = Moku.where(mjn_public: true).order(created_at: 'desc').limit(5) 
    render json: mokus, include:[:user, :moku_type]
end


コントローラで、mjn_publicというデーターがtrueになっているレコードを、
created_atが最新の方から数えて5つ拾ってもらうよ!
(ちなみにmjn_publicは、公開・非公開をbooleanで格納してる。)



それをmokusという変数に格納してもらうよ!



そうしたら、renderでjsonに。
ここまでは普通(らしい)




ここで+αの部分。
viewでuser.nameとか使いたいんだよ!
mokuとuserはhas_manyとbelongs_toで紐付けしてあるよ!

user →  has_many :mokus
moku →  belongs_to :user



でも、N+1問題(超たくさんSQLが発行されて、超絶重くなって、最悪落ちる)回避のために、
Lazy Loadingという機能が働くから、
このままだと紐付けされているのにuserモデルを参照してくれないんだってよ!




このままじゃmokusテーブルにあるカラムの情報しか使えないよ!




ここで朗報だよ!
紐付けしてあるモデルなら、
includeしてあげるといっしょにみてくれるんだってよ!すごいね!




include:[:user, :moku_type]のuserはUserモデル、moku_typeはMokuTypeモデルだよ!



これで、json化したmokuでも、
moku.user.nameとかでユーザ名を拾ってくれるよ!





includeしないと、moku.user.nameと書いても、
Lazy Loadingのおかげでuserが拾われないから、userの部分がnullになって、
moku.null.nameといった状況になるため、「そんな値はねえよ」とご指摘を食らうよ!



この点、Railsはすごいよ!



Rails大先生「moku.nilだと?なにがnilなの?user?
      いや、紐付けされてるUserってモデルがあるじゃねえか。
      多分これだろ?」


と推測してくれるから、紐付けしてさえあれば、

user = User.find(id: moku.user_id)


ってユーザーの検索を書かなくても、
moku.user.nameだけで紐づいてるuserの名前出してくれるよ!



天才か!



【mypage/index.html.erb】

<%= javascript_include_tag "mypage" %>


mypage.jsというファイルを別に作ったんで、そこのJSを読みにいってもらうよ!



ちなみに、ここも+αがあるよ!
同名の.coffeeってファイルがあると、どうもそっちを見にいっちゃうみたいだよ!



私はまんまとハマったよ!
せっかく作ったmypage.jsをみてくれないから、
mypage.coffeeをゴミ箱にぽいしてやったよ!




【mypage.js】

function getJustNowDatas() {
  $.ajax({
      type: 'get', 
   //routesに書いたajaxのためのURLに指定したリクエストメソッドを書く

      url: '/ajax/justnow.json' 
   //routesに書いたajaxのためのURLを書く

  }).done(function (response, status) { 
  //done→うまくいったら、 response→ブラウザから返ったデータ、status→結果。successとか。

      $('#justNowUl').empty() 
    //mypage/index.html.erbに書いてあるjustNowUlの中身を空に

      const mokus = response 
    //responseは↑の第一引数。ブラウザから返ってきたデーター

      console.log(mokus)

      for (let i = 0; i < mokus.length; i++) {
     //変数iを定義 mokusの要素の数より小さいうちはインクリメント

          const moku = mokus[i] 
    //定数mokuを定義 mokusに入っている要素のi番目を取得して定数mokuへ

          console.log(moku.id, moku.moku_type_id)

          const liElement = "<li>" + moku.user.name + "さんが" + moku.moku_type.name + "でMOKUを開始しました!" + "</li>" 
     //定数liElementを定義 moku.idをリスト形式で出力

          $('#justNowUl').append(liElement) 
   //justNowUlに対してliElementを追加 
      }
  })
}

$(document).ready(function () { 
//HTMLとか全部滞りなく読み取れたら、functionにかいたこと実行

  setInterval(getJustNowDatas, 5000) 
 //setIntervalさん、5000ms === 5秒ごとに、getJustNowDatasを実行してね
})

やっと大本命のJSのコードだよ!すでに3000文字超えたよ!




コードの意味を書き下してメモしてあるから見辛いね!ごめんね!



さて、このJSのコードの対象は↓の部分だよ!

const liElement = "<li>" + moku.user.name + "さんが" + moku.moku_type.name + "でMOKUを開始しました!" + "</li>" 

これ実行すると

【まきのさんがRuby on RailsでMOKUを開始しました!】

みたいな感じで表示されるよ!



で、ここにいつ開始したのか出すよ!
単にmoku.created_atを追加しちゃうと…


【2019-01-12 12:53:37 UTC まきのさんがRuby on RailsでMOKUを開始しました!】


ってなって、超ダサいよ!




created_atをいい感じで出す


そのために、今回はstrftimeという、Rubyの組み込みオブジェクトに助けてもらうことにしたよ!


strftime - リファレンス - - Railsドキュメント


対象のモデルにフォーマットのためのメソッドを作る!

【moku.rb】

def format_created_at
    self.created_at.strftime('%y/%m/%d  %H:%M')
end


このメソッドが呼ばれたら、呼んでくれたオブジェクトが持っている
created_atを、引数に書いた内容に変換してもらうよ!


変換できる内容はリファレンスにたくさんかいてあったよ!


対象のコントローラのrender jsonに渡してあげる!

【mokus_controller】

def justnow
    mokus = Moku.where(mjn_public: true).order(created_at: 'desc').limit(5) 
    render json: mokus, include:[:user, :moku_type], methods: [:format_created_at]
  end


最初に書いていたのとの違いは2行目だよ!


【土台の状態】

render json: mokus, include:[:user, :moku_type]


【今の状態】

render json: mokus, include:[:user, :moku_type], methods: [:format_created_at]


includeの後ろに methods: [:format_created_at] を加筆したよ!


view(JavaScript)で呼んであげる!


【mypage.js】

const liElement = "<li>" + moku.format_created_at + "   " + moku.user.name + "さんが" + moku.moku_type.name + "でMOKUを開始しました!" + "</li>"


これで、mokuに対してformat_created_atメソッドが呼ばれたから、

2019-01-12 12:53:37 UTC

2019/1/12 12:53

になるよ!

ちなみに

このやり方は、サーバー側、つまり Rails側で日時をいい感じに形成して
その形成したデーターをJSに渡すから、JSは表示してるだけ。



逆に、Rails側はデータを渡すだけで、フロント側、つまりJS側が受け取ったデーターを形成して表示するってやり方もできるんだって!


その時には、有名なmoments.jsってのを使うといいらしいよ!
私もそれで「○分前に」ってやってみたかったんだけれど、
ちょっとうまくいかなかったよ!



また後日調べてみるよ!