Rails で ajax を始めるときに理解しづらい点と、jQueryを使わず Vue.js を使う方法の整理
Rails 5.2.4.1で動かしています。6系でもたぶん一緒
基本的なことは Rails ガイドを参照していきます。
https://railsguides.jp/working_with_javascript_in_rails.html
respond_to に、format.js が必要
abc_controller.rb
def update
:
respond_to do |format|
if ovf.update(params[:id]) then
format.html { redirect_to polymorphic_url([ovf]), notice: '更新されました。' }
format.js
format.json { render :edit, status: :created, location: @ovf }
else
:
end
end
end
def update
:
respond_to do |format|
if ovf.update(params[:id]) then
format.html { redirect_to polymorphic_url([ovf]), notice: '更新されました。' }
format.js
format.json { render :edit, status: :created, location: @ovf }
else
:
end
end
end
Railsガイドによると
format.jsがrespond_toブロックの中にある点にご注目ください。これによって、コントローラがAjaxリクエストに応答できるようになります。
とのこと。
Controllerが (1) jsを返す方法と、(2)JSONを返す方法がある
(1) update.js.erb が必要
Railsガイドによると format.js に対応する事に続けて、次の記述がある。
続いて、対応するapp/views/users/create.js.erbビューファイルを作成します。実際のJavaScriptはこのビューで生成され、クライアントに送信されてそこで実行されます。
上記の Controller では update アクションから呼んでいるので、 update.js.erb が必要となる。これはJSを返す方法にあたる。Controller が、format.js で指定された JS ファイルを読み込んで、それをクライアント(ブラウザ)へ送って、JSが実行される。
Railsガイドでは「create.js.erbビューファイルを作成します」とあるが、partial も指定できる。
format.js {render partial: "reload" }
これで
create.js.erb の代わりに _reload.js.erb が読み込まれる。partial なのでアンダースコアに注意。
(2) app/assets/javascripts/application.js にAjaxを書く
application.js ではなく、分割した別ファイルにする場合も同様。
Railsガイドには記載がない。
この方法の場合、(1) に書いたJSの記述は app/assets/javascripts 配下の.js ファイルに移動する。CoffeeScript でもOK。
Controller は JSON を返すように変更する。
format.js{ render json: {ovf: @ovf}, status: :ok }
これで update.js.erb や partial で生成されたJSではなく、json で返すように変わる。
このJSONを使うように、app/assets/javascripts で JavaScript を書いておく必要がある。どう書くかについては、Railsガイド3.5 rails-ujsのイベントハンドラに記載がある。
3.5 rails-ujsのイベントハンドラ
Railsガイドの例では、次のように記載がある。
document.body.addEventListener('ajax:success', function(event) {
var detail = event.detail;
var data = detail[0], status = detail[1], xhr = detail[2];
})
上記によって、event.detail[0] から、Controller が返した JSON を取得できる。
turbolinks を使っている場合は、Railsガイド 5.2 ページ変更イベント に記載があるように、 turbolinks:load を使う。
function set_ajax() {
document.body.addEventListener('ajax:success', function(event) {
var detail = event.detail;
var data = detail[0], status = detail[1], xhr = detail[2];
alert("Success!" + data + status + xhr);
});
document.body.addEventListener('ajax:error', function(event) {
alert("fail");
});
}
document.addEventListener("turbolinks:load", set_ajax );
疑問:format.json はなんだ?
Controller には、次のような記述もある。scaffold で生成した場合についてくる。
format.json { render :edit, status: :created, location: @ovf }
view から data-remote: true した場合は、 format.js{} が反応しているので、 format.json{} は使われていない。
リクエスト時にJSONフォーマットを指定してくるAPIや、独自のJSがJSONでリクエストしている場合は必要。なければ不要なので消しておく。
cf.
Let'sプログラミング JSON/XML形式で出力する では、
http://localhost:3000/movies/index.json
のようにJSON形式を明示的にリクエストした場合に、 format.json が使われると記載されている。
その他
escape_javascript は j で書ける
<%= escape_javascript(render: @user) %>
<%= escape_javascript(render: @user) %>
の代わりに
<%= j(render: @user) %>
となる。
form_with
オプション local: true を指定しない。デフォルトでは入らなくなっているので、そのままでよい。
= form_with(model: @ovf, url: url, method: method ) do |f|
= f.submit(I18n.t('..button'), data: { "disable-with": "updating" })
$('#something') の記述を避ける
jQuery をやめようと思うので、 $(document)
や $('#something')
を避ける。参考になるドキュメントが一気に減ってしまう。
Vue でバインディングする
こちらを参考にした。
Rails + Ajax で Vue.js のバインディングを利用する
https://qiita.com/NaokiIshimura/items/c7c1330743757925e385
%p#script_update {{ message }}
:javascript
var script = new Vue({
el: '#script_update',
data: {
message: 'default message should be ID',
},
});
%p#script_update には、"default message should be ID" が表示されている。
Controller で生成した ovf を local 変数(同名のovf)として_reload.js.erb へ渡し、値をVueで定義した script.message へ入れる。
format.js {render partial: "reload", locals: {ovf: ovf },status: :ok }
script.message = <%= ovf.script %> ;
この方法がVueにレンダリングを任せられるので、楽そうな印象。
- data-remote: true を使って、Rails 標準のままrequestできる。
- Rails が js を返せる限りは動く。
- addEventListener が不要
- ただし、JSON を受け取る必要もない代わりに、View 内の Vue に密結合する。
- Vueがシンプルなうちは、Controller から view を意識している程度ではある
Vue で XHR
VueそのものはXHRを扱えない。他のライブラリと組み合わせる必要がある。
jQuery ではない方法では axios がある。Rails 標準の data-remote: true を使う場合は、追加のXHRは不要。
https://github.com/axios/axios
Rails の data-remote:true を動かす
Vue methods から submit するときは、data-remote が効かない。代わりにRails.fire を使うとよい。(が、公式ドキュメントが分からない)
checkbox_and_so_on: function(event){
// event.target.form.submit()
Rails.fire(event.target.form, 'submit')
}
cf. rails-ujs と form_with の使い方
https://www.bokukoko.info/entry/2017/12/22/194327
Vue で押さえておきたいこと
今からVue.jsを始める人のための「知るのを後回しにしてよい」n個のこと
https://qiita.com/fruitriin/items/3249bb24d60932bb42ee
Author And Source
この問題について(Rails で ajax を始めるときに理解しづらい点と、jQueryを使わず Vue.js を使う方法の整理), 我々は、より多くの情報をここで見つけました https://qiita.com/tettuan/items/32c5bc748704474391dd著者帰属:元の著者の情報は、元のURLに含まれています。著作権は原作者に属する。
Content is automatically searched and collected through network algorithms . If there is a violation . Please contact us . We will adjust (correct author information ,or delete content ) as soon as possible .