LoginSignup
7
6

More than 3 years have passed since last update.

rails 非同期通信

Last updated at Posted at 2019-10-15

今回はシンプルな投稿機能をrailsでjbuilderを使用して非同期通信を実装する

自分はjbuilderを使用した実装方法しかわからない、、

コードも綺麗とは言えませんが、自分が遭遇したエラーも何個か書いていこうと思うので

誰かの助けになればと思います

いずれjbuilderを使わないパターンやjs.erbを使ったパターンとの比較をしていきたい

完成品

Image from Gyazo

環境

ruby:2.5.1
rails:2.5.3
DB:mysql(Sequel Pro)
ブラウザ:Google
OS:Mac(10.14.6)

Github

作成手順

開発ファイルの作成

ターミナルで置きたいディレクトリに移動してから
rails new ajax -d mysql  #ここではajaxって名前のアプリにするけどなんでもいい

*補足

ターミナルで置きたいディレクトリに移動してから
rails new ajax

でもいいけど、このコマンドでアプリを作成するとDBがSQLiteで設定されたものが作られ、DBをSQLiteじゃないもの使っていた場合、この後入力するコマンドを打つとエラーが起こる。

そもそもrails newをする際にも色んなオプションをつけてアプリを作成することができる

今回は自分がmysqlを使用する為、最初の時点でDBの設定をmysqlに設定してコマンドを実行する

因みにもしオプションをつけずにコマンドを実行したらもう一度作成し直すか、config/database.ymlとGemfileをいじれば設定できる

↓先ほど作成したajaxのディレクトリで下記のコマンドを順に入力

ajax
bundle install #gemをインストール
rake db:create #DB作成
rails g scaffold Fruit name:string  #scaffoldを使用してコントローラ、モデル、ビュー、を全部作成
rake db:migrate  #先ほどscaffoldで作成したマイグレーションファイルを実行する

scaffoldでほとんどを作成
楽してすいません、、、

一応どんなファイルが作られるかだけ知っておきましょう
【Rails】 Scaffoldの使い方

ajax
rails s  #ローカルで開発用サーバーを起動する(これまでのコマンドがうまくいってるか確認  Googleでhttp://localhost:3000にアクセス)

うまくいっていれば下図のような画面が出てくる

スクリーンショット 2019-10-14 14.32.56.png

http://localhost:3000/fruits
を検索すると

スクリーンショット 2019-10-14 15.28.35.png
この画面が表示されるはず
 

ルーティングの設定

とりあえずルート画面を上図の画面に設定

config/routes.rb
Rails.application.routes.draw do
  root to: 'fruits#index'
  resources :fruits
end

 

hamlとbootstrapをインストール

次にgemをインストールしてhamlとbootstrapを使えるようにする

Gemfile
gem 'haml-rails'
gem 'bootstrap-sass'

 
hamlを使ってるうちにhtmlが書けなくなっていった為hamlを使用します、、
↓しっかりgemをインストール

ajax
bundle install

 
次にhtmlをhamlに変換するコマンドを入力

ajax
bundle exec rails haml:erb2haml

 
erbファイルは消していいよね?って出るのでyを入力

ajax
Would you like to delete the original .erb files? (This is not recommended unless you are under version control.) (y/n)

 
こんなが出たらOK

ajax
Task complete!
No .erb files found. Task will now exit.

 
次にbootstorapを使う準備をする

①ファイル名変更
application.css → application.scss
 

②application.jsに追記

assets/stylesheets/application.js
#上記省略
//
//= require rails-ujs
//= require activestorage
//= require bootstrap #追記
//= require turbolinks
//= require_tree .

 
③application.scss

assets/javascripts/application.scss
@import "bootstrap"; 

 
④scaffolds.scssのコメント化
scaffolds.scssの記述を全てコメント化、ファイルごと削除してもいい!
 

コントローラの設定

indexとcreateとdestroyアクションの記述変更

controllers/fruites.controller.rb
  def index
    @fruits = Fruit.all
    @fruit = Fruit.new  #追記
  end

  def create
    @fruit = Fruit.create(fruit_params)
      if @fruit.save
        respond_to do |format|
          format.html { redirect_to :root ,notice: 'fruits was successfully created!!!'}
          format.json
        end
      end
  end

  def destroy
    respond_to do |format|
      if @fruit.destroy
        format.html { redirect_to root_path, notice: 'フルーツ は destroyed.' }
        format.json { head :no_content }
      else
        format.html{redirect_to root_path, notice: '削除できてねえええええ'}
      end
    end
  end

 

ビューのページの記述変更

①index.html.haml編集

views/fruits/index.html.haml
.container 
  .row
    %h1 Listing fruit
    - if flash[:notice]
      %p= flash[:notice]

  .row
    %table.table.table-bordered.table-sortable
      %thead
        %tr
          %th Name
          %th
          %th
          %th
      %tbody.fruit_item
        - @fruits.each do |fruit|
          %tr.item
            %td
              = fruit.name
            %td
              = link_to 'Show', fruit
            %td
              = link_to 'Edit', edit_fruit_path(fruit)
            %td
              = link_to 'Destroy', fruit, data: {confirm: 'Are you sure?'}, method: :delete

  .row
    %h1 New fruit
    = render 'form'

②_form.html.haml編集

views/fruits/_form.html.haml
= form_for @fruit, class: 'a' do |f|
  .field
    = f.label :name
    = f.text_field :name, class: 'b'
    = f.submit 'Save', class: 'c'

今の所うまくいっていれば下記のようになる
Image from Gyazo
 

非同期通信の実装

①jqueryをインストール

Gemfile
#上記省略
gem 'jquery-rails'

 
②application.jsに追記

assets/stylesheets/application.js
#上記省略
//
//= require rails-ujs
//= require activestorage
//= require bootstrap
//= require jquery #追記
//= require turbolinks
//= require_tree .

 
③create.json.jbuilderのファイル作成

views/fruits/create.json.jbuilder
json.id @fruit.id
json.name @fruit.name

必要な値は「id」「フルーツの名前」なのでそれぞれをキーとしたjsonデータを生成するため上記のように追記
 

④fruits.jsのファイル作成

assets/javascripts/fruits.js
$(function(){
  function buildHTML(fruit){ //通信が成功するとdoneメソッドの引数にデータが入るようになっているため、これを利用してHTMLを組み立てる
    var html = `<tr class = "item ui-sortable-handle">
                  <td>
                    ${fruit.name}
                  </td>
                  <td>
                    <a href = /fruits/${fruit.id}>Show</a>
                  </td>
                  <td>
                    <a href = /fruits/${fruit.id}/edit>Edit</a>
                  </td>
                  <td>
                  <a data-confirm = "Are you sure?", rel = "nofollow", href = /fruits/${fruit.id}, data-method = "DELETE">Destroy</a>
                  </td>
                </tr>`
    return html;
  }
  $('#new_fruit').on('submit', function(e){ //'#new_fruit'の'submit'が押された時に発火
    e.preventDefault(); //これを書いてるせいで'submit'を押した際に要素にdisabledが付与される→最後の.alwasが書いてある行を足すことでそのdisabled要素を削除してる
    var formData = new FormData(this); //FormDataオブジェクトの引数はthisとなってる。イベントで設定したfunction内でthisを利用した場合はイベントが発生したDOM要素を指す。今回であればnew_commentというIDがついたフォームの情報を取得している
    $.ajax({
      url: "/fruits/", //ここはアクションのURLなのでrails routesで確認
      type: "POST", //ここはアクション名
      data: formData,
      dataType: 'json',
      processData: false,
      contentType: false
    })
    .done(function(data){ //非同期通信の結果として返ってくるデータは、done(function(data) { 処理 })の関数の引数で受け取る
      var html = buildHTML(data);
      $('.fruit_item').append(html) //htmlに追加
      $('.b').val('') //なんかエラー出るなーと思ったらvarと書き間違えていた(ここでは'submit'を押した後テキストボックスに空の要素を付与してる)
    })
    .fail(function(){ //エラーが置きた際
      alert('投稿できませんでした')
    })
    .always(function(){ //この記述を書いてないと連続で投稿できない
      $(".c").removeAttr("disabled")
    })
  })
});

以上で実装は終了
再度サーバーを立ち上げ直して

ajax
rails s

 
うまくいっていればくるっとした通信のマークが何も動かないはずです
スクリーンショット 2019-10-15 23.54.36.png

 
うまく実装できました?
_form.html.hamlでクラス名'a'とか'b'とか使ってましたけど、めんどくさくてつけなかっただけでちゃんと名前つけてください笑
決して真似しちゃいかん気がする

まだコード自体、綺麗にできる余地はあるものの一旦これであげたいと思います
指摘事項あれば教えて頂けると嬉しいです

今後、完成品のコードもgithubにあげていこうと思うので少々お待ちを
それでは

はてなブログもやっているので是非!
https://tanagram18.hatenablog.com/

7
6
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
7
6