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