[RUBY] Ajax bookmark function using Rails

Introduction

I will introduce how to change the bookmark function implemented in the Rails application from synchronous processing to asynchronous processing.

In a word, asynchronous communication ** "The screen will not be reloaded, but the screen display will change." ** I think it will be.

An example of how more ordinary people use asynchronous communication is when they like a Twitter post.

There are already many references on the net for explanations about Ajax, so I won't go into detail in this article. If you don't know about Ajax, please read the reference article below first.

Explanation of Ajax from a beginner's point of view

Bookmark function in synchronous communication

Add Ajax function to the bulletin board posting app. (Ignore the title and content as the post uses dummy text) image.png Currently, bookmarks can be registered by pressing the star mark on bulletin board posts. This time, bookmark the title "Kanjiru Happou".

erb:app/views/boards/_bookmark.html.erb


 <%= link_to bookmarks_path(board_id: board.id), id: "js-bookmark-button-for-board-#{board.id}", class:"float-right", method: :post do %>
 <%= icon 'far', 'star' %>
 <% end %>

By default, link_to performs synchronous communication, so if no option is specified, synchronous communication will be performed.

When you press the ☆ button, it is passed to the controller and executes the create action.

app/controllers/bookmarks_controller.rb


class BookmarksController < ApplicationController
  def create
    @bookmark = current_user.bookmarks.create(board_id: params[:board_id])
    flash[:success] = 'I created a bookmark'
    redirect_back(fallback_location: root_path)
  end
end

First, the first sentence current_user.bookmarks.create (board_id: params [: board_id]) is explained. The association between the User model and the Bookmark model has a one-to-many relationship.

app/models/user.rb


class User < ActiveRecord::ApplicationRecord
  has_many :bookmarks, dependent: :destroy
  has_many :bookmark_boards, through: :bookmarks, source: :board

By specifying has_many: bookmarks, you can create a Bookmark model from the associated User model. For example, the bookmark model consists of user_id, board_id, and the model is created with Bookmark.new (user_id:?, Board_id:?) (? Is a value). However, it creates a model in the same way as current_user.bookmarks.create (board_id: params [: board_id]), Bookmark.new above, but because user_id goes through the User model. No description is required, only the value of board_id is required.

redirect_back (fallback_location: root_path) will be the page that the redirect destination is currently viewing if you set the fallback_location: option to root_path. In other words, even if the route is set to the home page in the routing, the redirect destination here reloads the current page.

The screen will be reloaded and the star mark will change from ☆ to ★.

image.png

This is because either the ☆ mark or the ★ mark is displayed on each bulletin board as a conditional branch.

erb:app/views/boards/_bookmark_button.html.erb


 <% if current_user.bookmark?(board) %>
 <%= render 'unbookmark', { board: board } %>
 <% else %>
 <%= render 'bookmark', { board: board } %>
 <% end %>

current_user.bookmark? (Board) is defined as follows.

app/models/user.rb


  def bookmark?(board)
    bookmark_boards.include?(board)
  end

This uses has_many: bookmark_boards, through:: bookmarks, source:: board in the previous association description. Is the target bulletin board included in the set of bookmarked posts (= bookmark_boards) of the user who is currently logged in withcurrent_user.bookmark? (Board)(=include? (Board) It means).

If true, render the page with the ★ mark. On the contrary, if it is not included, the ☆ mark, which is a bookmark registration button, is displayed.

erb:app/views/boards/_unbookmark.html.erb


 <%= link_to bookmark_path(current_user.bookmarks.find_by(board_id: board.id)), id: "js-bookmark-button-for-board-#{board.id}", class:"float-right", method: :delete do %>
 <%= icon 'fas', 'star' %>
 <% end %>

erb:app/views/boards/_unbookmark.html.erb


 <%= link_to bookmarks_path(board_id: board.id), id: "js-bookmark-button-for-board-#{board.id}", class:"float-right", method: :post do %>
 <%= icon 'far', 'star' %>
 <% end %>

Introduction of asynchronous communication

From here, we will introduce day-synchronous communication.

However, before that, you need to install jQuery as a preliminary preparation, so if you have not done so, please install it first. How to install jQuery in Rails + How to check

The installation flow is as follows.

① Modify the bookmark controller ② Make bookmark button ajax ③ Added bookmark button switching process

① Modify the bookmark controller

Asynchronous communication does not redirect, so remove the redirect method from the controller.

app/controllers/bookmarks_controller.rb


class BookmarksController < ApplicationController
  def create
    @bookmark = current_user.bookmarks.create(board_id: params[:board_id])
    flash[:success] = 'I created a bookmark'
    # redirect_back(fallback_location: root_path) <=Delete!!!
  end
end

This will not redirect the page.

② Make bookmark button ajax

link_to is synchronous communication by default, but you can make it ajax by setting remote: true as an option.

erb:app/views/boards/_unbookmark.html.erb


<!-- remote:Add true-->
 <%= link_to bookmarks_path(board_id: board.id), id: "js-bookmark-button-for-board-#{board.id}", class:"float-right", remote: true, method: :post do %>
 <%= icon 'far', 'star' %>
 <% end %>

This allows you to set from synchronous communication to asynchronous communication.

What changes in a Rails application with remote: true is that the move create action is still performed on the controller. What changes is that after the create action is executed, ** the executed controller name and the file of the executed action name + js.erb ** that exists directly under the directory of the corresponding view are executed. It's a little confusing, but in this example, the executed action name + js that exists directly under the executed controller name (bookmarks_controller.rb) and the corresponding view directory (app/views/bookmarks). It means running the .erb file (create.js.erb).

③ Added bookmark button switching process

And finally, use jQuery to change the screen display asynchronously and without redirects.

As mentioned above, we need to create create.js.erb, so create create.js.erb directly under app/views/boards.

erb:app/views/bookmarks/create.js.erb


$("#js-bookmark-button-for-board-<%= @board.id %>").replaceWith("<%= j(render('boards/unbookmark', board: @board)) %>");

In link_to displaying the ☆ mark, the id is specified as follows.

erb:app/views/boards/_unbookmark.html.erb


 <%= link_to bookmarks_path(board_id: board.id), id: "js-bookmark-button-for-board-#{board.id}", class:"float-right", remote: true, method: :post do %>
 <%= icon 'far', 'star' %>
 <% end %>

Specify the element of link_to that displays the star mark with$ ("# js-bookmark-button-for-board-<% = @ board.id%>"). As you can see from the text, you can use <% =%> and <%%> in js.erb as well as html.erb. You can get the id of the target bulletin board by setting <% = @ board.id%>. (The instance variable @ board is defined by the create action.)

Use the replaceWith method to render only the part of the file that displays the ★ mark with the bookmarg. This will switch the ☆ mark to the ★ mark without redirecting.

Recommended Posts

Ajax bookmark function using Rails
Search function using [rails] ransack
[Rails] Tag management function (using acts-as-taggable-on)
[Rails] Create an evaluation function using raty.js
[Rails] Category function
Rails follow function
Implemented follow function in Rails (Ajax communication)
[Rails 6] Asynchronous (Ajax) follow function is implemented
Multiple image upload function using Rails Carrierwave
[Rails] Notification function
[Rails] Implementation of search function using gem's ransack
[Rails 6] Implementation of inquiry function using Action Mailer
Create authentication function in Rails application using devise
[Rails] Implementation of image enlargement function using lightbox2
Implement star rating function using Raty in Rails6
[Note] Summary of rails login function using devise ①
Follow function (Ajax) implementation
[rails] tag ranking function
Rails search function implementation
[Ruby on Rails] Asynchronous communication of posting function, ajax
[Rails] Test of star evaluation function using Raty [Rspec]
Implement user follow function in Rails (I use Ajax) ②
[Rails] Implementation of multi-layer category function using ancestry "Preparation"
[Rails] When using ajax, be aware of "CSRF measures".
[Rails] Implementation of multi-layer category function using ancestry "seed"
Implement user follow function in Rails (I use Ajax) ①
Rails learning How to implement search function using ActiveModel
Try to implement tagging function using rails and js
Implement application function in Rails
Rails implementation of ajax removal
[Rails] Implementation of multi-layer category function using ancestry "Editing form"
Rails fuzzy search function implementation
[Rails] Implement User search function
Introduced graph function with rails
Try using view_component with rails
Ruby on Rails Email automatic sending function setting (using gmail)
SNS authentication using Rails google
Implement follow function in Rails
[Rails] Save images using carrierwave
[Rails] Implementation of multi-layer category function using ancestry "Creation form"
Japaneseize using i18n with Rails
[Rails 6] Implementation of search function
[Rails] Implementation of category function
[Rails] Implementation of tagging function using intermediate table (without Gem)
[Rails] Implement event end function (logical deletion) using paranoia (gem)
[Rails] Test code using Rspec
Organize Rails routing using draw
Implement category function using ancestory
[Rails] (Supplement) Implemented follow function
Login function implementation with rails
[Rails] EC site cart function
Error when using rails capybara
[Rails] Implementation of tutorial function
[Rails] Try using Faraday middleware
Detailed tips when using Rails
[Rails] Implement image posting function
[Rails] Implementation of like function
[Rails] I tried to implement "Like function" using rails and js
[Rails 6] Star-shaped review using Raty.js
[Rails] Implement community membership application / approval function using many-to-many associations
[Rails 6] Pagination function implementation (kaminari)