【Rails】AjaxでJavaScriptの変数をコントローラーに渡す方法

【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の記事がこれ。

jQuery内からRailsのActionを叩く

 

とりあえず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すると、

binding.pry

 

しっかり「@sample」と「@count」に問題と番号が入っています。

「@sample[@count]」も成功。

 

5、しかし問題は解決しなかった

頑張ってAjaxまでしたのに、これで完了ではなかった。

 

JSから持ってきた変数をコントローラーでインスタンス変数として作り変えたものの、

@sample.field_idのような形で、@sampleからfield_idを取得することができない。

ターミナル画面2

もちろん@sampleには「field_id」がちゃんと入っている。

ターミナル画面3

 

また、この方法で作ったインスタンス変数はアソシエーションもできないみたいだ。

これではインスタンス変数を再度作り直した意味がない。

 

今回は残念ながらここで終了。

なんかを理解してないんだろうと思うが、ややこしいわほんと。

 

やり方が間違っている可能性も大ですし、

問題点として浮上する可能性の多さが、気持ちをげんなりさせてきます。

 

 

以上ありがとうございました。

保存保存

保存保存

保存保存

返信を残す

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です

CAPTCHA