今回はシンプルな投稿機能をrailsでjbuilderを使用して非同期通信を実装する
自分はjbuilderを使用した実装方法しかわからない、、
コードも綺麗とは言えませんが、自分が遭遇したエラーも何個か書いていこうと思うので
誰かの助けになればと思います
いずれjbuilderを使わないパターンやjs.erbを使ったパターンとの比較をしていきたい
完成品
環境
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のディレクトリで下記のコマンドを順に入力
bundle install #gemをインストール
rake db:create #DB作成
rails g scaffold Fruit name:string #scaffoldを使用してコントローラ、モデル、ビュー、を全部作成
rake db:migrate #先ほどscaffoldで作成したマイグレーションファイルを実行する
scaffoldでほとんどを作成
楽してすいません、、、
一応どんなファイルが作られるかだけ知っておきましょう
【Rails】 Scaffoldの使い方
rails s #ローカルで開発用サーバーを起動する(これまでのコマンドがうまくいってるか確認 Googleでhttp://localhost:3000にアクセス)
うまくいっていれば下図のような画面が出てくる
http://localhost:3000/fruits
を検索すると
ルーティングの設定
とりあえずルート画面を上図の画面に設定
Rails.application.routes.draw do
root to: 'fruits#index'
resources :fruits
end
hamlとbootstrapをインストール
次にgemをインストールしてhamlとbootstrapを使えるようにする
gem 'haml-rails'
gem 'bootstrap-sass'
hamlを使ってるうちにhtmlが書けなくなっていった為hamlを使用します、、
↓しっかりgemをインストール
bundle install
次にhtmlをhamlに変換するコマンドを入力
bundle exec rails haml:erb2haml
erbファイルは消していいよね?って出るのでyを入力
Would you like to delete the original .erb files? (This is not recommended unless you are under version control.) (y/n)
こんなが出たらOK
Task complete!
No .erb files found. Task will now exit.
次にbootstorapを使う準備をする
①ファイル名変更
application.css → application.scss
②application.jsに追記
#上記省略
//
//= require rails-ujs
//= require activestorage
//= require bootstrap #追記
//= require turbolinks
//= require_tree .
③application.scss
@import "bootstrap";
④scaffolds.scssのコメント化
scaffolds.scssの記述を全てコメント化、ファイルごと削除してもいい!
コントローラの設定
indexとcreateとdestroyアクションの記述変更
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編集
.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編集
= form_for @fruit, class: 'a' do |f|
.field
= f.label :name
= f.text_field :name, class: 'b'
= f.submit 'Save', class: 'c'
非同期通信の実装
①jqueryをインストール
#上記省略
gem 'jquery-rails'
②application.jsに追記
#上記省略
//
//= require rails-ujs
//= require activestorage
//= require bootstrap
//= require jquery #追記
//= require turbolinks
//= require_tree .
③create.json.jbuilderのファイル作成
json.id @fruit.id
json.name @fruit.name
必要な値は「id」「フルーツの名前」なのでそれぞれをキーとしたjsonデータを生成するため上記のように追記
④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")
})
})
});
以上で実装は終了
再度サーバーを立ち上げ直して
rails s
うまくいっていればくるっとした通信のマークが何も動かないはずです
うまく実装できました?
_form.html.hamlでクラス名'a'とか'b'とか使ってましたけど、めんどくさくてつけなかっただけでちゃんと名前つけてください笑
決して真似しちゃいかん気がする
まだコード自体、綺麗にできる余地はあるものの一旦これであげたいと思います
指摘事項あれば教えて頂けると嬉しいです
今後、完成品のコードもgithubにあげていこうと思うので少々お待ちを
それでは
はてなブログもやっているので是非!
https://tanagram18.hatenablog.com/