While creating a bulletin board site in a Rails project, I had the opportunity to implement an asynchronous like feature using remote: true
and the js.erb file
.
I will leave the procedure here as a memorandum.
Rails 5.0
It is assumed that create favorites_table
and define model association
have already been done.
association:
users - has_many :posts, has_many :favorites
posts - belongs_to :user, has_many :favorites
favorites - belongs_to :user, belongs_to :post
Prepare to use jQuery within Rails. First, introduce the gem.
Gemfile
gem 'jquery-rails'
** bundle install
** in the terminal.
Then add the description to ʻapplication.js`.
application.js
# Rails5.Before 1
//= require jquery
//= require jquery-ujs
#Version is Rails 5.For 1 or later
//= require jquery
//= require rails-ujs
This time, I'm using Rails 5.0, so please require
jquery_ujs
.
In this case, make sure to ** require jquery first **.
By the way, rails-ujs
is installed by default from Rails 5.1
, so you can just require it in application.js.
Describe the routing using the post method for the create action and the delete method for the destroy action. You can specify the Prefix name by writing as: as an option.
routes.rb
post '/favorite/:post_id' => 'favorites#create', as: 'like'
delete '/favorite/:post_id' => 'favorites#destroy', as: 'unlike'
Define like create and destroy.
app/controllers/favorites_controller.rb
class FavoritesController < ApplicationController
before_action :set_post
def create
@favorite = Favorite.create(user_id: current_user.id, post_id: @post.id)
end
def destroy
@favorite = Favorite.find_by(user_id: current_user.id, post_id: @post.id)
@favorite.destroy
end
private
def set_post
@post = Post.find(params[:post_id])
end
end
It is made into a partial template so that it can be reused easily.
erb:app/views/users/show.html.erb
<%= render 'posts/posts', posts: @posts %>
erb:app/views/users/_post.html.erb
<% posts.each do |post| %>
<div id="favorite-<%= post.id %>">
<%= render partial: "favorites/favorite", locals: { post: post } %>
</div>
<% end %>
In order to fire an event with js, specify a selector with id or class, but this time it is necessary to include the id of that post in the id to determine which post you like. You can specify an id like id = "post-1" by writing as above.
erb:app/views/favorites/_favorite.html.erb
<% if Favorite.find_by(user_id: current_user.id, post_id: post.id) %>
<%= link_to "How nice", unlike_path(post.id), method: :delete, remote: true, class: "btn btn-default" %>
<% else %>
<%= link_to "How nice", like_path(post.id), method: :post, remote: true, class: "btn btn-success" %>
<% end %>
<%= post.favorites.length %>
Add remote: true to the link_to of the like button.
This description allows you to call the js.erb file where you would normally call the html.erb file that corresponds to the action called link_to.
Therefore, communication will be performed asynchronously without page transition.
Finally, the number of likes is displayed as <% = post.favorites.length%>
.
First, create a js.erb file corresponding to each action of create and destroy.
app/views/favorites/create.js.erb
app/views/favorites/destroy.js.erb
erb:app/views/favorites/create.js.erb
$("#favorite-<%= @post.id %>").html("<%= j(render partial: 'favorites/favorite', locals: { post: @post }) %>");
erb:app/views/favorites/destroy.js.erb
$("#favorite-<%= @post.id %>").html("<%= j(render partial: 'favorites/favorite', locals: { post: @post }) %>");
First, specify the selector, but specify it so that it corresponds to ʻid = "favorite- <% = post.id%>`. Then, use jQuery's html () method to replace the html of the specified selector.
What to replace
" <% = j (render partial:'favorites / favorite', locals: {post: @post})%> "
part calls _favorite.html.erb
of the partial template.
(J in front of render is an alias for escape_javascript, a method that escapes line breaks and parentheses.)
This completes the implementation of the asynchronous like function!
Thank you for reading this far. If you find any mistakes, please let us know.
Recommended Posts