Ruby on Rails 비동기 통신 (ajax)에 대한 되돌아보기
비동기 통신으로 하고 싶었던 것은 이하의 2점.
① 특정 상품을 즐겨찾기 등록 또는 삭제
② 즐겨찾기 목록에서 삭제
전제 조건
테이블
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.rbbelongs_to :user
belongs_to :product
user.rbhas_many :favorites, dependent: :destroy
product.rbhas_many :favorites, dependent: :destroy
def favorited_by?(user)
Favorite.where(user_id: user.id).exists?
end
루트
rutes.rbresources :products do
resource :favorites, only: [:create, :destroy]
end
실장①(상품의 즐겨찾기 추가・삭제)
products 컨트롤러는 다음과 같습니다
products_controller.rbdef show
@product = Product.find(params[:id])
end
다음으로 즐겨찾기 버튼을 부분화. (사용자 디렉토리에 작성)
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.rbdef 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) %>");
이것으로 즐겨찾기 목록에도 비동기 기능을 구현할 수 있었다.
실장한 후의 반성점·감상
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
belongs_to :user
belongs_to :product
has_many :favorites, dependent: :destroy
has_many :favorites, dependent: :destroy
def favorited_by?(user)
Favorite.where(user_id: user.id).exists?
end
resources :products do
resource :favorites, only: [:create, :destroy]
end
products 컨트롤러는 다음과 같습니다
products_controller.rb
def show
@product = Product.find(params[:id])
end
다음으로 즐겨찾기 버튼을 부분화. (사용자 디렉토리에 작성)
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.rbdef 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) %>");
이것으로 즐겨찾기 목록에도 비동기 기능을 구현할 수 있었다.
실장한 후의 반성점·감상
def index
@favorites = current_user.favorites
end
<% 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 %>
<div class="row">
<div class="col-sm-6 offset-3" id="favorites_index">
<%= render 'users/favorites/form', favorites: @favorites %>
</div>
</div>
$("#favorites_index").html("<%= j(render 'users/favorites/form', favorites: @favorites) %>");
풀어 감동했다. 단지 흐름을 이해하고 있으면 헤매는 곳에서도 없었다고 느꼈다.
Reference
이 문제에 관하여(Ruby on Rails 비동기 통신 (ajax)에 대한 되돌아보기), 우리는 이곳에서 더 많은 자료를 발견하고 링크를 클릭하여 보았다 https://qiita.com/qz7_start/items/2430feca6df9ccf87257텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
우수한 개발자 콘텐츠 발견에 전념 (Collection and Share based on the CC Protocol.)