I will explain how to implement the post application function and cancel function using Rails.
As a rough flow, we will implement it according to the following procedure.
Posts can have multiple applicants, and users can subscribe to multiple posts. As a result, posts and users have a many-to-many relationship and require an intermediate table.
Also, in order to distinguish between the poster and the applicant even within the same user, we will define the applicant as taker
.
If the model name of the post is Post
, then you can create an intermediate table called post_takers.
To create an intermediate table, first type the following command in the terminal to create a model.
$ rails g model PostTaker
Open the completed migration file and write as follows.
2020XXXXXXXXXX_create_post_takers.rb
class CreatePostTakers < ActiveRecord::Migration[6.0]
def change
create_table :post_takers do |t|
t.references :post, foreign_key: true
t.references :taker, foreign_key: {to_table: :users}
t.timestamps
end
end
end
The point here is the t.references: taker, foreign_key: {to_table:: users}
part.
By writing like this, you can refer to the users table while defining the name of the applicant taker
as the foreign key of the intermediate table.
Reference article: https://qiita.com/publichtml/items/1fba15d8071fab66d043
Next, write the association in the model.
user.rb
class User < ApplicationRecord
has_many :post_takers, foreign_key: "taker_id", dependent: :destroy
end
post.rb
class Post < ApplicationRecord
has_many :post_takers, dependent: :destroy
has_many :takers, through: :post_takers, dependent: :destroy
end
post_taker.rb
class PostTaker < ApplicationRecord
belongs_to :taker, class_name: 'User', foreign_key: 'taker_id'
validates_uniqueness_of :post_id, scope: :taker_id
end
belongs_to: taker, class_name:'User', foreign_key:'taker_id'
in post_taker.rb is
By writing in this way, you can associate with the applicant associated with the User model.
Reference article: https://qiita.com/gyu_outputs/items/421cc1cd2eb5b39e20ad
Also, validates_uniqueness_of: post_id, scope:: taker_id
is
We have written such validation to prevent more than one same combination of post and applicant from being registered.
Describe the action of applying as take
and the action of canceling as cancel
in the routing as follows.
routes.rb
Rails.application.routes.draw do
resources :posts do
member do
get 'take'
get 'cancel'
end
end
end
In the above, member is used to include the id of the post in the path. Reference article: https://qiita.com/hirokihello/items/fa82863ab10a3052d2ff
Add the following description to the controller.
posts_controller.rb
class PostsController < ApplicationController
before_action :set_post
def show
@user = @post.user
end
def take
#Create an intermediate table record between the post and the logged-in user
PostTaker.create(post_id: @post.id, taker_id: current_user.id)
#Show flash message (If you don't want to show the flash message, you don't have to write it)
flash[:notice] = 'The application is complete.'
#Redirect to post details page
redirect_to action: "show"
end
def cancel
#Extract records by the corresponding post and logged-in user from the intermediate table
post_taker = PostTaker.find_by(post_g_id: @post.id, taker_id: current_user.id)
post_taker.destroy
flash[:notice] = 'Cancellation is complete.'
redirect_to action: "show"
end
private
def set_post
@post = Post.find(params[:id])
end
end
Finally, create a view of the application button and you're done! The following code is written in haml.
show.html.haml
-#Show the button only if the poster and the logged-in user do not match
- if @user.id != current_user.id
-#Cases are classified according to whether or not the logged-in user is included in the applicants for the relevant post.
- if @post.taker_ids.include?(current_user.id)
= link_to "Cancel application", cancel_posts_path(@post.id), data: { confirm: "Do you want to cancel the application for this post?" }
- else
= link_to "Apply", take_posts_path(@post.id), data: { confirm: "Would you like to apply for this post?" }
Recommended Posts