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