【Railsでアプリ開発中】プログラミング初心者の勉強ブログ #32
こんにちは。
32日目。どうしてもJavaScriptで定義した変数をRailsコントローラーに渡したいあなたへ。
学習内容
【オリジナルアプリ開発「免許学科試験学習アプリ」】
- Ajaxについてもう一度学ぶ(ドットインストールjQuery入門)
- Ajaxでコントローラへのアクセス方法
- Ajaxで変数を持たせる
感想
今回も「免許学科試験学習アプリ」に搭載する、
「JSで動く一問一答機能」を作っていきます。
正直軽い気持ちで「一問一答機能」つけよう思ってたんですけど、
こんな長引いて尚できてない状況になるとは思ってませんでした。
とにかく<script>タグからの値の出し入れが難しい。
もうちょっとRailsとJSうまいこと連携しないものなのか。
というのも、
前回(【Rails】RailsからJavaScriptにインスタンス変数を渡す方法を考える【DIVE INTO CODE】)やった内容で
「gon」というGemでなんとか
Rails => JavaScript
の変数渡しができたんですけど、
今度は
JavaScript => Rails
の変数渡しができないという。
いい方法、誰か教えてください。
まあ自分で問題解決能力を養うしかないので、自力でやりきることを意識。
最初にドットインストールでjQuery入門編のAjaxの回でもう一度復習。
そのあとはひたすらコードを眺めてました。
とにかく試したこと書いていきます。
JavaScript => Railsの変数渡しで試してみたこと
1、直接<script>タグ内に<% @(インスタンス変数) %>を使ってRubyを書く。
当然アウト。コントローラーで作った@questionみたいなインスタンス変数は全てJSでは使えませんでした。
だからこそ前回「gon」をインストールしたわけで。
まあ無理ですよね。
2、htmlメソッドやappendメソッドを使ってHTMLを書き換える。
アウト。変数を「gon.sample」パターンと「@sample」パターンどちらも試しましたがダメでした。
var element = ('#questionModal').children().remove(); #一旦#questionModalモーダル内の子要素を全て削除 element.append('<%= gon.sample[gon.count].content %>'); element.fadeIn(); #モーダル内に問題を表示。(gon.sampleという配列の、gon.count番目の、問題文contenntを取得)
これだとブラウザモーダル内に「[object]」という文字が表示され、実際の問題が取得できてませんでした。
「console.log(gon.sample[gon.count])」ってやると、コンソール上ではちゃんと問題が表示されるんですが、ブラウザに上がってきません。
惜しいです。
どこで互換性が切れてるのか、僕がどっかで間違えているのわかりませんが。
とにかく無理でした。
3、Ajax通信でJSで定義した変数を、一旦Railsコントローラーへ渡す。
一回コントローラーにJSの変数を渡してから、アクションを叩いてインスタンス変数を再度作り直してHTMLで使うという戦法です。
参考にしたQiitaの記事がこれ。
とりあえずAjax書いてみた。
$(function(){ $('.nextQuestion').click(function() { #省略 gon.count += 1; #もともと0を代入していたgon.countに+1。 $.ajax({ url: '/itimon_ittous/update', #itimon_ittousコントローラーのupdateアクションへのパス。 type: 'GET', # getかpostか選択 dataType: 'html', # htmlやjsonなど形式を選択。 async: true, # 非同期ならtrue、同期ならfalse。 data: { count: gon.count, sample: gon.sample }, # 渡したいパラメータを定義。 }); #省略 }); });
調べたらこの形たくさん出てきます。
初心者なので一つ一つどれも何もかも、意味がわかりませんでした。
何とか理解し始めた部分や気づきを書いていきます。
注意事項① ルーティングについて
url: '/itimon_ittous/update',
ここでパスを指定します。
必ずrailsのルーティングを確認することが大事。
なければルーティングをconfig/route.rbファイルに付け足す。
この場合、itimon_ittousコントローラのupdateアクションを叩くことになる。
注意事項② データタイプについて
dataType: 'html',
railsの表示したいviewファイルの形式に合わせます。
コントローラがレンダリングするviewを意識する必要があります。
今回はhtmlファイルに合わせています。
注意事項③ データについて
data: { count: gon.count, sample: gon.sample },
ここでパラメータで渡したい値を定義します。
上の場合、コントローラーにて、
itimon_ittous_controller.rbに
def update @sample = params[:sample] @count = params[:count] end
と記述することで、JS上で定義されている「gon.count」と「gon.sample」がコントローラーに渡せます。
4、実装した結果
とりあえずJSの変数をコントローラーに渡すことに成功。
jsの方でイベントを起こし、(今回の場合「次の問題へ進む」ボタンをクリック)
ターミナルを見ると、
html形式でパラメータが送られてきていることがわかります。
また、コントローラーの方でbinding.pryすると、
しっかり「@sample」と「@count」に問題と番号が入っています。
「@sample[@count]」も成功。
5、しかし問題は解決しなかった
頑張ってAjaxまでしたのに、これで完了ではなかった。
JSから持ってきた変数をコントローラーでインスタンス変数として作り変えたものの、
@sample.field_idのような形で、@sampleからfield_idを取得することができない。
もちろん@sampleには「field_id」がちゃんと入っている。
また、この方法で作ったインスタンス変数はアソシエーションもできないみたいだ。
これではインスタンス変数を再度作り直した意味がない。
今回は残念ながらここで終了。
なんかを理解してないんだろうと思うが、ややこしいわほんと。
やり方が間違っている可能性も大ですし、
問題点として浮上する可能性の多さが、気持ちをげんなりさせてきます。
以上ありがとうございました。