苦手なajaxちょい復習。
ajaxの要点。つめてはないので、若干不正確かもしれないが、流れを思い出すためにメモ。
コントローラー側の値をhtml側が要求したjson形式に整える場所。
右側を左側に突っ込む感じ
json.text @post.text
json.date @post.created_at
って感じで突っ込むと
例えばコントローラーで@postにpostsテーブルのレコード突っ込んでるならそのレコードのtextカラムをjsonの方でもキーがtextとして受け取るし、created_atで日付を突っ込んでjsonの方ではキーがdateとして受け取ってる。
テキストを送信するイベントだったとすると、送信したテキストの文言が
text:送った文言
date:作成された日付
って感じでhtmlの方に帰ってくる。その読みかえ(キーがcreated_atだった物がhtmlではdateになる読みかえ。)をjson.jbuilderでやってる。
てか多分ダイレクトに数字とか文字もキーに打ち込めると思う。
通信成功したらdoneとかで関数呼び出すだろうけど、そこで適当な名前の引数でデータ全体を受け取ってキーで値を取り出す感じ。
ここがrubyと勝手が違うところで、引数渡す時は特に具体的な値を書くワケじゃなくて(多分アクション名.json.jbuilderに書いた)データ全体を渡すと思って良さそう。だからデータ受け取る側のdoneメソッドとかに書いてある引数の名前は適当につけても多分大丈夫で、その引数.キーっていう形で欲しい値を取得するって流れだったと思う。
要は真引数はデータ丸ごと全部で、仮引数名がdoneメソッドとかに書いてある引数で、仮引数の中のjsonデータの塊に何ていうkeyを使えば(左側)、どんな値をゲットできるのか(右側)を書く場所がアクション名.json.jbuilderという風に理解すればいいかな。
逆にhtml側からコントローラーにキーを指定してjsonデータを渡すには、jsファイルで
$.ajax({ type: "GET", url: "/users", data: { keyword: input }, dataType: "json" })
みたいな感じでdata:{キー: 渡す値}とか書いてあげる。これは前に書いた記事からの抜粋だが、その時は
let input = $("#インプットフォームのid名").val();
て感じでフォームに入力した値をinputっていう変数に代入してdata:{key:input}にして渡していた。
コントローラー側では詳しい説明は割愛するが
@users = User.where(['name LIKE ?', "%#{params[:keyword]}%"] ).where.not(id: current_user.id).limit(10)
みたいな感じでparams[:keyword]で受け取って処理に使い、@usesに欲しいユーザー達の情報をぶち込んでた。
ちなみに話は戻って、こいつをまたhtml側にjsonで返すためにアクション名.json.jbuilderを使うワケなんだけど、@usersには複数のユーザー情報が入っているので(つまり配列なので)、
json.array! @users do |user|
json.id user.id
json.name user.name
end
って感じでarray!を使ってjsonの形式のデータを使い易いように整えてる。
この後の記述としてはかなり割愛して要点だけざっくり言うと
.done(function(users) { users.forEach(function(user) { addUser(user); })
users(コントローラーでは@users)一人一人に対して(引数でこいつら渡して)addUserを実行してるっていう流れだった。addUserはhtmlビルドしてappendするっていうよくある流れが書いてある関数なんだけど、そのhtmlビルドの際にuser.nameとかuser.idとかを使う。
____流れと関係ない追記ゾーン___
追記※疑問なんだが、コントローラに@productsとか別の配列もあったらどうなるんだ?
さらに追記※
こんな感じで質問したら
カリキュラムでajaxのインクリメンタルサーチの部分見直してて疑問に思ったのですが、json.array!で複数の配列を渡したらdoneメソッド側ではどうやって受け取るんでしょうか?@usersだけでなく@postsもjbuilderに記述したような場合です。配列一つならforEachで受け取ってるのもわかるですが、二つ渡されたらどうするんでしょうか?
こんな感じで返ってきたので
1つ1つ分けて記述した方が確実な方法だと思うのですが複数の配列で実装したい感じでしょうか?
こんな感じで確認したら
いいえ、基本的に分けて発火させるという認識でいればいいなら大丈夫です。実装しにくい場合はアクションとjbuilderを小分けにしていくのが基本的な方針と思ってよろしいでしょうか?
それでOKってことだった
おっしゃる通りです!
だから配列ごちゃごちゃ詰め込んだjbuilderは基本的には書かないで、必要な処理の数だけちゃんとjsonのルーティング、コントローラーのアクション、jbuilder, js側での処理(doneメソッドとか)、を用意してあげるって方針でいこう、と思った。
________追記終了_______
かなり極端な話
json.array! @users do |user|
json.dogdogdog user.id
json.catcatcat user.name
end
とか書いて,jsで
.done(function(fruits)) {
fruits.forEach(man){
addUser(man)
}
}
とか書いて
jsのもっと前の方で
addUser(hoge){
let html = `<div>idが${hoge.dogdogdog}のユーザーの名前は${hoge.catcatcat}</div>`
return html
}
みたいに定義しとくなんてことも可能ではあるんだろう。もちろんやるべきじゃないけど。
あともう一つだけごっちゃになり易いので補足しとくと、カスタムデータ属性は別にajaxとかjsonとかと直接関係する訳じゃなくてjsとかjqueryでデータを取得するために設定するものって感じだと思う。関係ないとは言わないけどごっちゃにしないように。下の記事で使い方わかると思う。あとjqueryで使う場合の仕様とかも。
https://www.sejuku.net/blog/38263
https://www.webprofessional.jp/how-why-use-html5-custom-data-attributes/
こんな感じでサーバーと通信しなくても普通に使うし、通信したかったら(コントローラーに値送りたかったから)、先に出てきたようにdata: {キー名: バリュー}という形で送信して、コントローラ側ではparams[:キー名]で値を取得できる。
それと上の記事にも書かれてるようにdata()とattr()をごっちゃにしないように注意。