12
12

More than 3 years have passed since last update.

【Ruby on Rails】投稿機能の非同期通信、ajax化

Last updated at Posted at 2020-09-06

目標

ajax.gif

開発環境

ruby 2.5.7
Rails 5.2.4.3
OS: macOS Catalina

前提

※ ▶◯◯ を選択すると、説明等が出てきますので、
  よくわからない場合の参考にしていただければと思います。

流れ

1 gem 'jquery-rails'を導入
2 非同期通信にしたい箇所を部分テンプレート化
3 remote: trueを記述
4 js.erbファイルを作成
5 controllerのリダイレクト先を削除

うまくいかない場合は、
ターミナルでActionView::Template::Errorが表示される場合が多く、
大体は変数の定義忘れが多いと思います。
あとはid名やrenderの記述を間違わなければ、うまくいくはずです。

gem 'jquery-rails'を導入

Gemfile
gem 'jquery-rails'
ターミナル
$ bundle install
app/assets/javascript/sapplication.js
//= require rails-ujs
//= require activestorage
//= require jquery      <--追加
//= require turbolinks
//= require_tree .

部分テンプレート化、 remote: trueの追加

今回は新規投稿画面の非同期通信を行っていきます、

app/views/posts/new.html.erb
<h1>Posts#new</h1>
<span>現在ログイン中のユーザー:<%= current_user.name %></span>

<--- form_for  form_withに変更し、, data: {remote: true}を記述 --->
<%= form_for(@post, url: posts_path) do |f| %>
<--- --->

    <div>
        <%= f.label :タイトル %><br>
        <%= f.text_field :title, autofocus: true %> <-- idを追加
    </div>
    <div>
        <%= f.label :中身 %><br>
        <%= f.text_area :body %>
    </div>
    <div><%= f.submit "投稿する" %></div>
<% end %>
<table>
    <thead>
        <tr>
            <th>投稿者名</th>
            <th>タイトル</th>
            <th>本文</th>
            <th></th>
            <th></th>
            <th></th>
        </tr>
    </thead>
    <tbody>  <-- idを追加

<--- ここから --->
        <% @posts.each do |post| %>
            <tr>
                <td><%= post.user.name %></td>
                <td><%= post.title %></td>
                <td><%= post.body %></td>
                <td><%= link_to "詳細", post_path(post) %></td>
                <td><%= link_to "編集", edit_post_path(post) %></td>
                <td><%= link_to "削除", post_path(post), method: :delete %></td>
            </tr>
        <% end %>
<--- ここまでを部分テンプレート化 --->

    </tbody>
</table>

修正した記述が以下の通り。

app/views/posts/new.html.erb
<h1>Posts#new</h1>
<span>現在ログイン中のユーザー:<%= current_user.name %></span>
<%= form_with model:[@post], data: {remote: true} do |f| %>
    <div>
        <%= f.label :タイトル %><br>
        <%= f.text_field :title, autofocus: true, id: "text" %>
    </div>
    <div>
        <%= f.label :中身 %><br>
        <%= f.text_area :body %>
    </div>
    <div><%= f.submit "投稿する" %></div>
<% end %>
<table>
    <thead>
        <tr>
            <th>投稿者名</th>
            <th>タイトル</th>
            <th>本文</th>
            <th></th>
            <th></th>
            <th></th>
        </tr>
    </thead>
    <tbody id="post">
        <%= render 'posts/new', posts: @posts %>
    </tbody>
</table>

補足
render 'posts/new', posts: @posts は
app/views/posts/_new.html.erbの部分テンプレートを読み込みます。
そしてローカル変数に変更したpostsに@postsを代入します。
※その際、createとdestroyに@postsを定義する必要があります。
これは後ほど記述していきます。

部分テンプレートは以下のファイルを作成し、@postsをローカル変数に変更。
削除ボタンにもremote:trueを記述。

app/views/posts/_new.html.erb
<% posts.each do |post| %>
    <tr>
        <td><%= post.user.name %></td>
        <td><%= post.title %></td>
        <td><%= post.body %></td>
        <td><%= link_to "詳細", post_path(post) %></td>
        <td><%= link_to "編集", edit_post_path(post) %></td>
        <td><%= link_to "削除", post_path(post), method: :delete, remote: true %></td>
    </tr>
<% end %>

js.erbファイルを作成

app/views/create.js.erb
$('#post').html("<%= j(render 'posts/new', posts: @posts) %>");
$("text_area").val("");
$("#text").val("");
app/views/destroy.js.erb
$('#post').html("<%= j(render 'posts/new', posts: @posts) %>");

補足
$('#post').html("<%= j(render 'posts/new', posts: @posts) %>"); は
render部分のhtmlを更新するという意味です。
$("text_area").val(""); はform_withのtext_areaを空白に
$("#text").val(""); はform_withのtext_fild(idで指定済み)を空白に
html以外にもappendなども使えるのでおすすめです

controllersのリダイレクト先を削除

app/controllers/posts_controller.rb
  def create
    @posts = Post.all  <---追加
    @post = Post.new(post_params)
    @post.user_id = current_user.id
    if @post.save
      redirect_to new_post_path  <---削除
    else
      render :new
    end
  end

  def destroy
    @posts = Post.all  <---追加
    @post = Post.find(params[:id])
    @post.destroy
    redirect_to request.referer  <---削除
  end

修正後。

app/controllers/posts_controller.rb
  def create
    @posts = Post.all
    @post = Post.new(post_params)
    @post.user_id = current_user.id
    if @post.save
    else
      render :new
    end
  end

  def destroy
    @posts = Post.all
    @post = Post.find(params[:id])
    @post.destroy
  end
12
12
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
12
12