I created a simple app with Ruby on Rails, so I had a hard time I wrote an article because I wanted to make a note of the points I devised as a memorandum in the future.
・ Mac ・ Git installed ・ Ruby 2.6.5 ・ Rails 6.0.3.4 ・ Visual Studio Code
It is an application that allows users to share clothes. When I usually buy clothes, I often refer to the clothes worn by others, so it would be convenient to have an app that allows me to share photos of the clothes I have, impressions of coming, and prices. I thought, I created it.
The following three tables are used this time. A user can post multiple clothes (fuku). In addition, the intermediate table allows users to like the posted clothes.
column | type |
---|---|
id | string |
name | string |
string | |
profile_image_id | string |
column | type |
---|---|
id | string |
title | string |
body | text |
user_id | integer |
image_id | string |
column | type |
---|---|
id | string |
user_id | integer |
fuku_id | integer |
When creating the login authentication function, it takes time to create everything from scratch, so I used devise, which is easy to implement.
$rails generate devise :install
The setting method required for the login function will appear, so add the code. In addition, create a User model based on devise.
$rails g devise User
At this time, the User model based on devise has only email and password columns by default, so add name and profile_image_id to the migration file.
$rails g migration add_name_to_users name:string profile_image_id:string
$rails db:migrate
Add the profile_image and name fields to the new registration view as well.
ruby:new.html.erb
<div class="field">
<%= f.label :profile image%>
<%= f.attachment_field :profile_image %>
</div>
<div class="field">
<%= f.text_field :name, autofocus: true, placeholder:"name", autocomplete: "name"%>
</div>
I thought that the user's new registration function could be implemented with this, but even if I set the name and profile image on the new registration screen It was not reflected in the database. Upon investigation, it was found that devise only accepts email addresses and passwords when registering new by default. By describing the strong parameter in application.controller as shown below, the added column can also be received.
ruby:application.controller.rb
def configure_permitted_parameters
devise_parameter_sanitizer.permit(:sign_up, keys: [:name, :profile_image])
end
I want to implement the function to post images to each of the user model and Fuku model, so I decided to use refile. There is a carrierwave in another similar gem, but refile is a relatively new one created by the creator of carrierwave as a successor, so I used refile this time. I referred to this article on Qiita. https://qiita.com/salvage0707/items/2614c97a1f256027ef71
We will implement a function that allows you to like the posted clothes.
(1) "Like user id: user_id" and "Like clothes id: fuku_id" are saved in "Intermediate table: likes table". ② The like button switches depending on "Like" and "Like completed".
First, create a table (likes table) that stores "liked users" and "liked clothes".
$rails g model like user_id:integer fuku_id:integer
$rails db:migrate
We will describe the association for the model. User and Fuku are one-to-many, User and Like are one-to-many, Fuku and Like are also one-to-many, so
user.rb
has_many :fukus
has_many :likes
fuku.rb
belongs_to :user
has_many :fukus
like.rb
belongs_to :user
belongs_to :fuku
It will be.
Likes are nested inside fukus to like the posted clothes. I felt that resource is very convenient because routing is automatically trained just by writing one line.
resources :fukus do
resources :likes, only:[:create, :destroy]
end
Make a likes controller.
$rails g controller likes
Then on the clothing details page, edit the view so that the logged-in user can like it. Make sure that the logged-in user behaves differently when they already like it and when they don't.
ruby:app/views/fukus/show.html.erb
<% if Like.find_by(user_id:current_user.id, fuku_id:@fuku.id) %>
<p><%= link_to 'Liked', fuku_likes_path(@fuku), method: :delete %></p>
<%else%>
<p><%= link_to 'How nice', fuku_likes_path(@fuku), method: :post %></p>
<%end%>
Describe the likes controller as follows, and store the id of the user who liked and the post in the likes table of the user who is logged in with the create action. The destroy action is used to cancel the like.
likes_controller.rb
def create
@like=Like.new(user_id:current_user.id, fuku_id:params[:fuku_id])
@lika
redirect_back(fallback_location: root_path)
end
def destroy
@like =Like.find_by(user_id:current_user.id, fuku_id:params[:fuku_id])
@like.destroy
redirect_back(fallback_location: root_path)
end
Then edit the controller and view so that you can see the likes on the user detail page.
@ fukus
→ Get user_id of clothes posted by each user
@ likes
→ Get the user_id of the likes pressed by each user
users_controller.rb
def show
@user=User.find_by(id:params[:id])
@fukus=Fuku.where(user_id:@user.id)
@likes=Like.where(user_id:@user.id)
end
ruby:app/users/show.html.erb
<% @likes.each do |like| %>
<% fuku=Fuku.find_by(id:like.fuku_id)%>
<%= link_to(fuku_path(fuku)) do %>
<%=attachment_image_tag fuku,:image,class:"thumbnail150" %>
<%end%>
<%end%>
This completes the implementation of the like function.
before_action :authenticate_user! By writing at the beginning of the controller, the processing performed there can be executed only by the logged-in user. Also, for example, if you want to allow users who are not logged in to perform only the index action, describe as follows.
class FukusController < ApplicationController
before_action :authenticate_user!, except: [:index]
def index
@fukus=Fuku.all
end
def show
@fuku=Fuku.find_by(id:params[:id])
end
end
By creating the app from scratch, I think I have acquired the minimum knowledge of CRUD processing. I still get errors frequently, but I think that by referring to similar articles, I have gained the ability to investigate and solve them myself. I would like to continue learning more and add, for example, a function that allows users to send messages to each other, and a function that allows users to search by clothing brand, type, and price range. Also, I'm not good at implementing the front end, so I'd like to study that area as well.
Recommended Posts