Railsでフォームを非同期で送信して更新処理を行う
タイトルママです。
Railsアプリを書いていて、画面遷移を起こさずに更新処理を行って画面にも反映させたかったのでざっくりやってみた。*1
例として適当に簡単なアプリケーションを作りたいと思います。
rails new test-app rails g model user name:string age:integer rake db:migrate rails g controller users index create
ユーザーを追加して一覧表示するだけのアプリです。超簡単。
ユーザーは名前と年齢の項目を持っています。コントローラは一覧表示用にindexアクションとユーザーの追加用にcreateアクションでいいでしょう。
あと、個人的な好みでhamlを使います。
#Gemfile gem 'haml-rails'
あくまでも僕の好みなので、すっ飛ばしても構いません。
次にconfig/routes.rbを弄くります。コントローラを作った時にできていた2行は消して、次の一行を足してRESTっぽい感じにしたいと思います。
#config/routes.rb resources :users, only: [:index, :create]
さて、まずはUsersController#indexから
#users_controller.rb def index @all_users = User.all end
普通に全取得して、画面に渡すだけ。
そしたら次はindex.html.hamlかな。
-# index.html.haml %h2 ユーザー一覧 %ul{id: 'user_list'} - @all_users.each do |user| %li= "#{user.name}, #{user.age}" = form_tag '#', {id: 'user_form', onsubmit: 'return false;'} do .field 名前 = text_field_tag 'user[name]' .field 年齢 = text_field_tag 'user[age]' = button_tag 'ユーザーを追加する', {id: 'user_add_button', type: 'button'}
ほい。こんな感じでいいでしょう。
form_tagのremoteオプションでの非同期処理はcallbackの受け方が分からなかった*2ので今回は使わないです。あと、テキストフィールドにフォーカス当たっている時にEnterでsubmitするのは今回邪魔なんで消しています。で、submitを使うと困ったことになるので、button_tagで代用します。*3
次に実際に非同期処理を行うjQueryの方を作りこみましょう。
#users.js.coffee $ -> init() init = -> $user_list = $('#user_list') $user_add_button = $('#user_add_button') $user_add_button.on 'click', -> $user_name = $('#user_name') $user_age = $('#user_age') _name = $user_name.val() _age = $user_age.val() _data = 'user' : 'name' : _name 'age' : _age $.ajax type : 'POST' url : '/users' dataType : 'json' data : _data .done (user) -> $user_list.append("<li>"+user.name+", "+user.age+"</li>") .fail -> alert("進捗ダメです")
_dataのとこでJSONオブジェクトを組み立てます。この構造地味に大事です。あとはいいかな。処理が正常に終了した場合、jsonオブジェクトを受け取り、そこから名前と年齢を取得しています。ダメだったらalertで「進捗ダメです」と教えてくれます。
さて、最後。UsersController#createですね。
#users_controller.rb def create user = User.create(user_params) render json: user end private def user_params params.require(:user).permit(:name, :age) end
ちゃんとStrong Parametersを使っているあたりえらいですね。これだいぶ適当に書いているのでこんなんですけど、ちゃんとエラー処理とかもいれましょうね。
ざくっと書きましたけど、こんな感じでRailsアプリケーションで非同期処理ができました!
もう少しスマートな方法あるといいんだけど、非同期処理のcallbackを受けたいし、DOMも弄りたいしってなるとこれしかないのかなーとか思います。