[Rails] Implement community membership application / approval function using many-to-many associations

What you want to do

Implement application / approval mechanism

In particular?

"A user (Konishi) wants to join a certain community, This is an implementation example in the case of "subscription requires the approval of the community administrator (Onishi)".

Rough image

キャプチャ.PNG

Processing flow overview

  1. On the relevant community screen, the user (Konishi) presses the "Apply" button.
  2. The user (Konishi) is added to the application waiting list of the relevant community. The administrator looks at the application waiting list screen of the relevant community and decides whether to approve the applicant.
  3. To approve the application, press the approval button. The applicant user joins the community and is removed from the application waiting list.
  4. To reject the application, press the reject button. It will be deleted from the application waiting list.

environment

Ruby 2.6.5 Rails 5.2.4.2 mysql 5.7

Current application feature configuration

I am creating an application that allows users to belong to various communities. --user model: Holds user information for using the app --Community model: Holds community information --belonging model: Holds community information to which the user belongs. Users can belong to multiple communities.

The following sources are excerpts of related parts only

user.rb


class User < ApplicationRecord

  has_many :belongings, dependent: :destroy
  has_many :applies, dependent: :destroy
  has_many :communities, through: :belongings #The community to which the user belongs

end

community.rb


class Community < ApplicationRecord
    has_many :belongings, dependent: :destroy
    has_many :applies, dependent: :destroy
    has_many :users, through: :belongings #Users who belong to the community

    #Returns true if the user belongs to the community
    def user_belonging?(user)
      users.include?(user)
    end

end

belonging.rb


class Belonging < ApplicationRecord
    belongs_to :user
    belongs_to :community
    validates :user_id, presence: true
    validates :community_id, presence: true

    validates  :user_id, uniqueness: { scope: :community_id }
    validates  :community_id, uniqueness: { scope: :user_id }

end

Add Apply model and keep application status.

Apply Apply Add model routing, controller, and view files.

Routing (excerpt)

routes.rb


Rails.application.routes.draw do
  root 'home#index'

  resources :communities do
    resources :applies, only: %i[index create destroy]
    resources :belongings, only: %i[index create destroy]
  end

  resources :users, only: [:index, :show]

end

1. On the relevant community screen, the user (Konishi) presses the "Apply" button.

--Application button (placed on the community details screen) (views/communities/show.html.erb)

show.html.erb


<!--If the logged-in user belongs to the community-->
<% if @community.user_belonging?(current_user) %>
    <%= link_to 'Withdraw', community_belonging_path(@community, @belonging), method: :delete, data:{ confirm: "community"#{@community.name}Withdraw from the membership. Is it OK?" } ,class:"mini-red-link-btn font-bold text-line-none" %>
<!--If you are not affiliated with the community but are logged in-->
<% elsif current_user %>
    <% if @apply %>
        <%= link_to 'Cancellation of application', community_apply_path(@community, @apply), method: :delete, class: "mini-red-link-btn font-bold text-line-none" %>
    <% else %>
        <%= link_to 'Application for membership', community_applies_path(@community), method: :post, class: "mini-green-link-btn font-bold text-line-none" %>
    <% end %>

The application button will be displayed under the following conditions.

  1. If you are already a member of the community: A button to unsubscribe is displayed
  2. If you haven't joined the community yet: the application button will be displayed
  3. If you have already applied for membership: Display the application cancellation button

--After pressing the application button (create action occurs)

applies_controller.rb


class AppliesController < ApplicationController

  def create
    current_user.applies.create(community_id: apply_params[:community_id])
    redirect_to community_url(apply_params[:community_id]), notice: "I applied for membership"
  end

  private

    def apply_params
      params.permit(:community_id)
    end

end

Do not use Ajax and make sure that the redirect to the same screen occurs. (You may use Ajax)

** The application information is now added to the apply model. ** **

2. The user (Konishi) is added to the application waiting list of the relevant community. The administrator looks at the application waiting list screen of the relevant community and decides whether to approve the applicant.

Next, check the waiting list. The administrator (Onishi) opens the "Application waiting list screen" from the relevant community screen.

--Link to application waiting screen (community details screen) (views/communities/show.html.erb)

show.html.erb


<% if user_admin_flg(current_user,@community) == 1 %>
    <%= link_to "Approval waiting list", community_applies_path(@community), class:"btn btn-primary" %>
<% end %>

Click the link to open the application waiting list screen.

--Application waiting list screen (views/applies/index.html.erb)

index.html.erb


<div class="container applicant-wrapper">
    <h3>List of users waiting for approval</h3>
    <div class="row">
        <% @applies.each do |app| %>
        <div class="col-6">
            <% if app.user.image.attached? %>
                <%= link_to app.user.image, user_path(app.user), class:"user-icon" %>
            <% else %>
                <%= link_to user_path(app.user) do %>
                    <%= image_tag ("no_image.png "), class:"user-icon" %>
                <% end %>
            <% end %>
            &nbsp<%= app.user.username %><br>
            <%= link_to "Approval", community_belongings_path(app.community, user_id: app.user.id, apply_id: app.id), method: :post, class:"mini-green-link-btn font-bold text-line-none" %>
            <%= link_to "Rejected", community_apply_path(app.community, app), method: :delete, class:"mini-red-link-btn font-bold text-line-none" %>
            <br>
        </div>
        <% end %>
    </div>
</div>

From the apply model, the application information to the relevant community is displayed in a list. On the same screen, an approval button and a rejection button are also arranged.

3. To approve the application, press the approval button. The applicant user joins the community and is removed from the application waiting list.

When you press the approve button, the following processing will be executed.

  1. The create action of the belongings controller is executed.
  2. Since it is deleted from the application waiting list, the corresponding application information of the Apply model is deleted.
  3. Redirect to the application waiting list screen

--belongings controller

belongings_controller.rb


class BelongingsController < ApplicationController

    def create
        @belonging = Belonging.create(community_id: belonging_params[:community_id], user_id: belonging_params[:user_id])
        Apply.find(belonging_params[:apply_id]).destroy!
        redirect_to community_applies_url(@belonging.community), notice:"「#{@belonging.user.username}", But the community:#{@belonging.community.name}I joined."
    end

    private

        def belonging_params
            params.permit(:community_id, :user_id, :apply_id)
        end

end

4. To reject the application, press the reject button. It will be deleted from the application waiting list.

If you press the reject button, the following processing will be executed.

  1. In order to delete from the application waiting list, the destroy action of the apps controller is executed and the corresponding application information of the Apply model is deleted.
  2. Redirect to the application waiting list screen

--applies controller

applies_controller.rb


class AppliesController < ApplicationController

  def destroy
    @apply = Apply.find(params[:id])
    @apply.destroy!
    @comminity = Community.find(params[:community_id])
    redirect_to community_url(@comminity), notice: "I canceled my application"
  end

end

That's it.

In the text, the apps controller and belongings controller are introduced separately for each action, but I will list them all together at the end.

applies_controller.rb


class AppliesController < ApplicationController

  def create
    current_user.applies.create(community_id: apply_params[:community_id])
    redirect_to community_url(apply_params[:community_id]), notice: "I applied for membership"
  end

  def destroy
    @apply = Apply.find(params[:id])
    @apply.destroy!
    @comminity = Community.find(params[:community_id])
    redirect_to community_url(@comminity), notice: "I canceled my application"
  end

  def index
    @applies = Apply.where(community_id: params[:community_id])
  end

  private

    def apply_params
      params.permit(:community_id)
    end

end

belongings_controller.rb


class BelongingsController < ApplicationController

    def create
        @belonging = Belonging.create(community_id: belonging_params[:community_id], user_id: belonging_params[:user_id])
        Apply.find(belonging_params[:apply_id]).destroy!
        redirect_to community_applies_url(@belonging.community), notice:"「#{@belonging.user.username}", But the community:#{@belonging.community.name}I joined."
    end

    def destroy
        @belonging = Belonging.find(params[:id])
        @belonging.destroy!
        @comminity = Community.find(params[:community_id])
        redirect_to community_url(@comminity), notice: "community"#{@comminity.name}I have withdrawn."    
    end

    private

        def belonging_params
            params.permit(:community_id, :user_id, :apply_id)
        end

end

Since the beginner thought and implemented the logic code with his own head, There may be mistakes and better implementations. I would appreciate it if you could point out.

I think this implementation gives you a better understanding of the many-to-many relationship.

Recommended Posts

[Rails] Implement community membership application / approval function using many-to-many associations
Implement application function in Rails
Create authentication function in Rails application using devise
Implement post search function in Rails application (where method)
[Rails] Implement User search function
Search function using [rails] ransack
[Rails] Implement event end function (logical deletion) using paranoia (gem)
Implement category function using ancestory
[Rails] Implement image posting function
[Rails] Tag management function (using acts-as-taggable-on)
Implement CSV download function in Rails
[Rails] Types of associations (one-to-many / many-to-many)
How to implement image posting using rails