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
Add Ajax function to the bulletin board posting app.
(Ignore the title and content as the post uses dummy text)
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 ★.

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 %>
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
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.
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).
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