In case you forget it, I have briefly summarized the implementation of the like function together with devise.
environment Rails 5.2 series Ruby 2.6 series
Library used devise Slim
$ cd
$ rails new favorite_function
$ cd favorite_function
Gemfile
gem 'slim-rails' #Provides a Slim generator
gem 'html2slim' #Converts ERB format files to slim format
gem 'devise'
$ bundle
$ rails g devise:install
create config/initializers/devise.rb
create config/locales/devise.en.yml
===============================================================================
Some setup you must do manually if you haven't yet:
1. Ensure you have defined default url options in your environments files. Here
is an example of default_url_options appropriate for a development environment
in config/environments/development.rb:
config.action_mailer.default_url_options = { host: 'localhost', port: 3000 }
In production, :host should be set to the actual host of your application.
2. Ensure you have defined root_url to *something* in your config/routes.rb.
For example:
root to: "home#index"
3. Ensure you have flash messages in app/views/layouts/application.html.erb.
For example:
<p class="notice"><%= notice %></p>
<p class="alert"><%= alert %></p>
4. You can copy Devise views (for customization) to your app by running:
rails g devise:views
===============================================================================
config/environments/development.rb
Rails.application.configure do
.
.
.
config.action_mailer.default_url_options = { host: 'localhost', port: 3000 }
.
.
.
end
$ rails g controller posts new index show
config/routes.rb
Rails.application.routes.draw do
root to: 'posts#index' #The root I want to set in the app_Specify url
resources :posts
.
.
.
end
ruby:app/views/layouts/application.html.erb
<p class="notice"><%= notice %></p>
<p class="alert"><%= alert %></p>
$ rails g devise:views
invoke Devise::Generators::SharedViewsGenerator
create app/views/devise/shared
create app/views/devise/shared/_error_messages.html.erb
create app/views/devise/shared/_links.html.erb
create app/views/devise/confirmations
create app/views/devise/confirmations/new.html.erb
create app/views/devise/passwords
create app/views/devise/passwords/edit.html.erb
create app/views/devise/passwords/new.html.erb
create app/views/devise/registrations
create app/views/devise/registrations/edit.html.erb
create app/views/devise/registrations/new.html.erb
create app/views/devise/sessions
create app/views/devise/sessions/new.html.erb
create app/views/devise/unlocks
create app/views/devise/unlocks/new.html.erb
create app/views/devise/mailer
create app/views/devise/mailer/confirmation_instructions.html.erb
create app/views/devise/mailer/email_changed.html.erb
create app/views/devise/mailer/password_change.html.erb
create app/views/devise/mailer/reset_password_instructions.html.erb
create app/views/devise/mailer/unlock_instructions.html.erb
$ bundle exec erb2slim app/views/ --delete
__ * Regarding the devise directory, if you convert it to Slim, an error will occur in devise / shared / _error_messages.html.slim, so fix it. __
ruby:devise/shared/_error_messages.html.slim
- if resource.errors.any?
#error_explanation
h2
#An error occurs in the following 3 lines, so fix it as follows
= I18n.t("errors.messages.not_saved",
count: resource.errors.count,
resource: resource.class.model_name.human.downcase)
ul
- resource.errors.full_messages.each do |message|
li
= message
ruby:app/views/layouts/application.html.slim
html
head
.
.
.
body
- if user_signed_in?
=link_to 'Log out', destroy_user_session_path, method: :delete
- else
=link_to 'sign up', new_user_registration_path
=link_to 'Login', new_user_session_path
.
.
.
・ If you don't know which path leads to which action in devise, check with the rails routes command.
$ rails g devise User
$ rails g model Post content:string user:references
$ rails g model Favorite user:references post:references
$ rails g migration add_columns_to_users username:string
$ rails db:migrate
-By setting model name: references
, foreign_key is automatically set in the migration file, and the association is also done in the model file.
-Since ```User and Post have a one-to-many `` `relationship, put a reference to Post to indicate that it is owned by User.
-User has multiple likes for Post` `,` `Post also has multiple likes from User`
Many-to-many
``, so in Favorite On the other hand, put up a reference indicating that it is owned by Post and User.
-Since it is not possible to add a column to the default User model created by ``` devise``, execute the column addition command and create data related to User such as name.
app/models/favorite.rb
class Favorite < ApplicationRecord
belongs_to :user
belongs_to :post
end
app/models/post.rb
class Post < ApplicationRecord
belongs_to :user
has_many :favorites
end
-You can call post.favorites when you want to like a post. You can get the number of likes by using post.favorites.count.
user.rb
class User < ApplicationRecord
devise :database_authenticatable, :registerable,
:recoverable, :rememberable, :validatable
has_many :favorites
has_many :favorite_posts, through: :favorites, source: :post
has_many :posts
end
-It is possible to call user.favorites when `` getting the likes given by the user
`.
-``` If you want to display posts that users like on your profile screen, there is `. At that time, you will be able to call user.favorite_posts. It uses the
through option
`` `to associate with the Post model through an intermediate table.
-The model used in through is ``` which must be associated first. In this case, favorites must be associated first.
-In source, describe the model name that is the reference source of the named model name.
has_many :Favorite model name, through: :Intermediate table, source: :The model name that is the reference source of the named model
---
### 9. Create controller
$ rails g controller posts new index show #Omitted if created when setting devise $ rails g controller users index show $ rails g controller favorites create destroy
· (Posts,) users, favorites controller
---
### 10. Implementation of user functions
#### 10-1. Editing routing
#### **`config/routes.rb`**
```ruby
Rails.application.routes.draw do
resources :users, only: [:index, :show] #For user list and profile screen
devise_for :users #For login mechanism
end
app/controllers/users_controller.rb
class UsersController < ApplicationController
before_action :authenticate_user! #User authentication provided by devise
def index
@users = User.all
end
def show
@user = User.find(params[:id])
end
end
ruby:app/views/users/index.html.slim
h1 user list
- @users.each do |user|
p
= link_to user.email, user
● show
ruby:app/views/users/show.html.slim
h1 user profile page
p
= @user.username
= @user.email
ruby:app/views/layouts/application.html.slim
body
- if user_signed_in?
.
.
.
+ = link_to 'My page', user_path(current_user)
+ = link_to 'User list', users_path
- else
.
.
config/routes.rb
Rails.application.routes.draw do
resources :users
devise_for :users
root to: 'posts#index' #Specify the post list as the root
resources :posts
end
app/controllers/posts_controller.rb
class PostsController < ApplicationController
def index
@posts = Post.all
end
def new
@post = Post.new
end
def create
@post = current_user.posts.new(post_params) # current_user represents the logged-in user provided by devise.
if @post.save
redirect_to @post
end
end
def show
@post = Post.find(params[:id])
end
private
def post_params
params.require(:post).permit(:content)
end
end
-When a new post is posted, the owner of the created post is the user who posted it, so set it to `current_user.posts`
. The user_id in the posts table now contains the id of current_user. (Note that this method cannot be used unless the ```User model and Post model are associated `` `)
● index
ruby:app/views/posts/index.html.slim
h1 post list
- @posts.each do |post|
p= link_to post.user.email, user_path(post.user.id)
p= link_to post.content
● new
ruby:app/views/posts/new.html.slim
h2 new post
= form_with model: @post do |f|
p
= f.label :content
= f.text_area :content
= f.submit 'Post'
● show
ruby:app/views/posts/show.html.slim
h1 post details page
p= @post.content
ruby:app/views/layouts/application.html.slim
body
- if user_signed_in?
.
.
.
= link_to 'Post list', posts_path
- else
.
.
ruby:app/views/posts/index.html.slim
h1 post list
- @posts.each do |post|
p= link_to post.user.email, user_path(post.user.id)
p= link_to post.content
- if user_signed_in? #A method provided by devise to check if a user is logged in
- if post.favorited_by?(current_user)
p= link_to post.favorites.count, post_favorites_path(post.id), method: :delete
- else
p= link_to post.favorites.count, post_favorites_path(post.id), method: :post
- else
= post.favorites.count
-``` Use user_signed_in?
`To make it visible only to the logged-in user.
-Since it is a `` mechanism that likes are added by the
create action and likes disappear by the
`destroy action, it is explicitly specified in the method of the link_to helper.
・ ``` If you like it, you want to display the delete link of the like ``, and if you haven't liked it yet, you want to display the link to create the like
, so
Check it with the favorited_by (current_user) method
`.
-The favored_by (current_user) method will be created after this.
-``` Post.favorites.count shows the number of likes of the post` ``.
app/models/post.rb
class Post < ApplicationRecord
belongs_to :user
has_many :favorites
+ def favorited_by?(current_user)
+ favorites.where(user_id: current_user.id).exists?
+ end
end
-Because it is a method that is called only for the Post model, it is defined as a Post instance method.
-Check if the id of the logged-in user exists in the user_id of the ``` favorites table``.
-It will be used like post.favorited_by (current_user). Let's make it a little easier
ruby:posts/index.html.slim
h1 post list
- @posts.each do |post|
.
.
.
- if post.favorited_by?(current_user)
#Show delete link of likes
- else
#Show Create Like Link
-This shows the following code.
- if post.favorites.where(user_id: current_user.id).exists?
#Delete link display
- else
#Show Create Like Link
-``` Get the id of the logged-in user `,` `user_id is the id of the logged-in user
from the favorites table of the acquired post, and `` check if it exists
I'm letting you.
-Returns true if it exists. `Like it means`
, so display the like delete link.
-Returns false if it does not exist.
I don't like it `` `, so display the like creation link.
config/routes.rb
Rails.application.routes.draw do
resources :users
devise_for :users
root to: 'posts#index'
resources :posts do
+ resource :favorites, only: [:create, :destroy]
end
end
-Favorites are nested in posts. This makes it easier to specify a path to like a post, such as post_favorites_path
.
app/controllers/favorites_controller.rb
class FavoritesController < ApplicationController
def create
favorite = current_user.favorites.build(post_id: params[:post_id])
favorite.save
redirect_to posts_path
end
def destroy
favorite = Favorite.find_by(post_id: params[:post_id], user_id: current_user.id)
favorite.destroy
redirect_to posts_path
end
end
-``` Stores the id of `` ,
liked posts in the favorites table of the logged-in user
`. And by saving it, it is regarded as giving a like.
-Obtain and delete the data in the favorites table where the idof the post that clicked
Unlike" matches the id of the user who is ``` `. By doing so, it is regarded as a dislike.
app/controllers/users_controller.rb
class UsersController < ApplicationController
before_action :authenticate_user!
def index
@users = User.all
end
def show
@user = User.find(params[:id])
@posts = @user.posts
@favorite_posts = @user.favorite_posts
end
end
・ In @posts
, I get normal posts to display normal posts.
・ In @favorite_posts
, the posts that the user likes are acquired. That's why app / models / user.rb was associated with the Post model under the name favorite_posts through the favorites table.
ruby:app/views/users/show.html.slim
h1 user profile page
p
= @user.username
h3 like
- @favorite_posts.each do |f_post|
p
= f_post.content
h3 post
- @posts.each do |post|
p
= post.content
・ The above shows posts that users like.
・ Below shows the posts posted by users.
-You can make it look like Twitter by switching by click event, but I will not do it here.
This completes the implementation of the like function.
https://qiita.com/kazukimatsumoto/items/14bdff681ec5ddac26d1
Recommended Posts