2
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

Ruby on Rails 非同期通信(ajax)についての振り返り

Last updated at Posted at 2020-07-04

カリキュラム学習・ポートフォリオ作成中、この機能を実装するのに苦戦したので、メモ。
非同期通信にしたかったのは以下の二点。

①特定の商品をお気に入り登録or削除する
お気に入りの作成。削除ボタン.gif

②お気に入り一覧から削除する
お気に入り一覧の削除ボタン.gif

前提条件

テーブル

schema.rb

  create_table "users", force: :cascade do |t|
()
  end
 create_table "products", force: :cascade do |t|
()
  end

  create_table "favorites", force: :cascade do |t|
    t.integer "user_id", null: false
    t.integer "product_id", null: false
    t.datetime "created_at", null: false
    t.datetime "updated_at", null: false
  end

モデル(アソシエーション)

favorite.rb
belongs_to :user
belongs_to :product

user.rb
has_many :favorites, dependent: :destroy
product.rb
has_many :favorites, dependent: :destroy

def favorited_by?(user)
  Favorite.where(user_id: user.id).exists?
end

ルート

rutes.rb
resources :products do
 resource :favorites, only: [:create, :destroy]
end

実装①(商品のお気に入り追加・削除)

productsコントローラは以下の通り

products_controller.rb
def show
  @product = Product.find(params[:id])
end

次にお気に入りボタンをパーシャル化。(userディレクトリ内に作成)

views/users/products/_favorite_button.html.erb
<% if product.favorites.where(user_id: current_user.id).exists? %>
  <%= link_to "お気に入りから削除",  users_product_favorites_path(product_id: product.id), method: :delete, remote: true %>
<% else %>
  <%= link_to "お気に入りに追加", users_product_favorites_path(product_id: product.id), method: :post, remote: true %>
<% end %>

ここでremote: trueを付けることで、非同期通信が可能になる。

products/show.html.erbで呼び出し

views/users/products/show.html.erb
<div id="favorites_buttons_<%= @product.id %>">
  <%= render 'users/products/favorite_button', product: @product %>
</div>

次はfavoritesのコントローラ。

fovorites_controller.rb
  def create
    @product = Product.find(params[:product_id])
    favorite = current_user.favorites.new(product_id: @product.id)
    favorite.save
  end

  def destroy
    @product = Product.find(params[:product_id])
    @favorites = current_user.favorites
    favorite = current_user.favorites.find_by(product_id: @product.id)
    favorite.destroy
  end

ここでリダイレクト先を指定しなければ、JSの処理を探しに行ってくれる。
最後に作成・削除した場合のJS処理を作成する。

views/users/favorites/create.js.erb
$("#favorites_buttons_<%= @product.id %>").html("<%= j(render 'users/products/favorite_button', product: @product) %>");
views/users/favorites/destroy.js.erb
$("#favorites_buttons_<%= @product.id %>").html("<%= j(render 'users/products/favorite_button', product: @product) %>");

show.html.erb内の、idで設定した範囲のみが、処理後書き換えられるようになる。

実装②(お気に入り一覧から削除)

fovoritesのコントローラは以下の通り作成

favorites_controller.rb
def index
  @favorites = current_user.favorites
end

非同期通信したい範囲をパーシャル化。

view/users/favorites/_form.html.erb
<% if favorites.present? %>
  <table class="table">
    <thead>
      <tr>
        <th colspan="3">商品</th>
      </tr>
    </thead>
    <tbody>
      <% favorites.each do |f| %>
        <tr>
          <td>
            <%= attachment_image_tag f.product, :image, :fill, 80, 80, format: 'jpeg', fallback: "no_image.jpg", size: '80x80' %>
          </td>
          <td><%= link_to f.product.name, users_product_path(f.product.id) %></td>
          <td><%= link_to "お気に入りから削除",  users_product_favorites_path(product_id: f.product.id), method: :delete, remote: true %></td>
        </tr>
      <% end %>
    </tbody>
  </table>
<% else %>
  <h3>
    お気に入りリストがありません。<br>
    商品ページから追加してみましょう
  </h3>
<% end %>

fovorites/index.html.erbで呼び出し

<div class="row">
  <div class="col-sm-6 offset-3" id="favorites_index">
    <%= render 'users/favorites/form', favorites: @favorites %>
  </div>
</div>

JSの処理に以下の1行を追加

views/users/favorites/destroy.js.erb
$("#favorites_index").html("<%= j(render 'users/favorites/form', favorites: @favorites) %>");

これでお気に入り一覧にも非同期機能が実装できた。

実装した上での反省点・感想

  • JSに記載しているインスタンス変数はそれぞれcreate・destroyメソッドから確認しているため、そっちでも定義してあげないといけないということが身にしみた。(考えてみれば当たり前だったが)
  • 実装①についてはググればよく出てくるが、②は見かけないので自力で
    解けて感動した。ただ流れを理解していれば迷うとこでも無かったなと感じた。
2
1
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
2
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?