[Ruby] [Rails] Implement application/approval function for community joining using many-to-many association

5 minute read

What you want to do

Implement application/approval mechanism

In particular?

“User (Konishi) wants to join a certain community, It is an implementation example in the case of “Approval of the community administrator (Onishi) is required for joining”.

Rough image

capture.PNG

Process flow overview

  1. On the relevant community screen, the user (Konishi) presses the “Apply” button.
  2. 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 determines whether to approve the applicant.
  3. To approve the application, press the approval button. The requesting user joins the community and is deleted from the waiting list.
  4. To reject the application, press the denial button. It will be deleted from the waiting list.

Environment

Ruby 2.6.5 Rails 5.2.4.2 mysql 5.7

Current application function configuration

We are creating applications that allow users to belong to various communities.

  • user model: Holds user information of application
  • community model: Holds community information
  • belonging model: Holds community information to which the user belongs. Users can belong to multiple communities. *User and community are in a many-to-many relationship through a belonging model.

Below is the relevant part of the source code

user.rb


class User <ApplicationRecord

  has_many :belongings, dependent: :destroy
  has_many :applies, dependent: :destroy
  has_many :communities, through: :belongings # 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 in the community

# Returns true if the user belongs to a 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

Apply Add a model and keep the application status.

Apply Adds 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.

  • Apply button (placed on the community details screen) (Views/communities/show.html.erb)

show.html.erb


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

Apply button is displayed under the following conditions.

  1. If you are already a member of the community: You will see a button to unsubscribe
  2. If you haven’t joined the community yet: the Apply button is displayed
  3. If you have already applied for membership: Display the application cancellation button
  • After pressing the Apply 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: "Subscribed"
  end

  private

    def apply_params
      params.permit(:community_id)
    end

end

Instead of using Ajax, make sure that a redirect to the same screen occurs. (Ajax can be used)

** You have now added your application information to the apply model. **

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

Next is confirmation of 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 list", community_applies_path(@community), class:"btn btn-primary" %>
<% end %>

Click the link to open the application waiting list screen.

  • Pending application 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>

The application information for the applicable community is displayed as a list from the apply model. On the same screen, an approval button and a rejection button are also placed.

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

When you press the approval button, the following process will be executed.

  1. The create action of the belongings controller is executed.
  2. The corresponding application information of Apply model is deleted because it is deleted from the waiting list.
  3. Redirect to the 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}" has joined the community: #{@belonging.community.name}. "
    end

    private

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

end

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

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

  1. In order to delete from the application waiting list, the destroy action of the applies controller is executed and the applicable application information of the Apply model is deleted.
  2. Redirect to the 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: "Subscription canceled"
  end

end

That’s it.

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

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: "Subscribed"
  end

  def destroy
    @apply = Apply.find(params[:id])
    @apply.destroy!
    @comminity = Community.find(params[:community_id])
    redirect_to community_url(@comminity), notice: "Subscription canceled"
  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}" has joined the community: #{@belonging.community.name}. "
    end

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

    private

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

end

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

With this implementation, I think you have a better understanding of many-to-many relationships.