Belay Board Simple Part 3: Comments
Published: 2023-11-23 04:58:07

https://github.com/Samuel-Lubliner/Belay-Board-Simple

https://github.com/users/Samuel-Lubliner/projects/2

## Post and delete comments on availabilities

Now that I have a calendar with availabilities, add Description and comments, I want to allow users to post and delete comments on availabilities. Comments made by the user who cerated the availability will be displayed as a description section. Comments made by guests will be displayed under the description as a comment section. 

`rails g model Comment body:text user:references availability:references`
`rails db:migrate`

### Associations

```rb
class Comment < ApplicationRecord
  belongs_to :user
  belongs_to :availability

  validates :body, presence: true
end

class Availability < ApplicationRecord
  #...
  has_many :comments, dependent: :destroy
end

class User < ApplicationRecord
  #...
  has_many :comments, dependent: :destroy
end
```

`rails g controller Comments`

```rb
class CommentsController < ApplicationController
  before_action :set_availability, only: [:create]
  before_action :set_comment, only: [:destroy]

  def create
    @comment = @availability.comments.new(comment_params)
    @comment.user = current_user

    if @comment.save
      redirect_to @availability, notice: 'Comment was successfully added.'
    else
      redirect_to @availability, alert: 'Unable to add comment.'
    end
  end

  def destroy
    @comment.destroy
    redirect_to @comment.availability, notice: 'Comment was successfully deleted.'
  end

  private

  def set_availability
    @availability = Availability.find(params[:availability_id])
  end
  

  def set_comment
    @comment = current_user.comments.find(params[:id])
  end

  def comment_params
    params.require(:comment).permit(:body, :availability_id)
  end
end
```

```rb
Rails.application.routes.draw do
  root "availabilities#index"

  devise_for :users

  resources :availabilities do
    resources :comments, only: [:create, :destroy]
  end
  

  resources :event_requests, only: [:create] do
    member do
      post :accept
      post :reject
    end
  end
```

```html
<div class="container mt-3">
  
  <div class="row">
    <div class="col-md-8">
      <%= render @availability %>

      <% if current_user && @availability.user != current_user %>
  <% unless @availability.event_requests.exists?(user: current_user) %>
    <%= form_for(current_user.event_requests.new, url: event_requests_path, remote: true, class: 'd-flex justify-content-end') do |f| %>
      <%= f.hidden_field :availability_id, value: @availability.id %>
      <%= button_tag(type: "submit", class: "btn btn-primary", id: "join-event-button") do %>
        <i class="fas fa-user-plus"></i>Me
      <% end %>
    <% end %>
  <% end %>
<% end %>

<p>
  <strong>Guests</strong>
</p>

<ul id="guest_requests_list" class="list-group">
  <% @event_requests.each do |event_request| %>
    <li id="event_request_<%= event_request.id %>" class="list-group-item d-flex justify-content-between align-items-center">
      <%= render partial: 'event_request', locals: { event_request: event_request } %>
      <% if event_request.status == 'pending' && @availability.user == current_user %>
        <%= button_to 'Accept', accept_event_request_path(event_request), method: :post, remote: true, class: 'btn btn-success btn-sm', data: { turbo: false } %>
        <%= button_to 'Reject', reject_event_request_path(event_request), method: :post, remote: true, class: 'btn btn-danger btn-sm', data: { turbo: false } %>
      <% end %>
    </li>
  <% end %>
</ul>

<h3>Description</h3>
<div class="card mb-3">
  <div class="card-body">
    <% @availability.comments.each do |comment| %>
      <% if comment.user == @availability.user %>
        <div class="d-flex justify-content-between">
          <p><%= comment.body %></p>
          <% if current_user == comment.user %>
            <div class="dropdown">
              <button class="btn btn-secondary dropdown-toggle" type="button" id="dropdownMenuButton<%= comment.id %>" data-bs-toggle="dropdown" aria-expanded="false">
                <i class="fas fa-ellipsis-v"></i>
              </button>
              <ul class="dropdown-menu" aria-labelledby="dropdownMenuButton<%= comment.id %>">
                <li>
                  <%= button_to 'Delete', 
                                availability_comment_path(@availability, comment),
                                method: :delete,
                                data: { confirm: 'Are you sure?' },
                                class: 'dropdown-item' %>
                </li>
              </ul>
            </div>
          <% end %>
        </div>
      <% end %>
    <% end %>
  </div>
</div>

<h3>Comments</h3>
<div class="card mb-3">
  <div class="card-body">
    <% @availability.comments.each do |comment| %>
      <% unless comment.user == @availability.user %>
        <div class="d-flex justify-content-between">
          <p><strong><%= comment.user.username %>:</strong> <%= comment.body %></p>
          <% if current_user == comment.user %>
          <% end %>
        </div>
      <% end %>
    <% end %>
  </div>
</div>

<%= form_for([@availability, @availability.comments.new], html: { class: "mb-3" }) do |f| %>
  <div class="form-group">
    <%= f.text_area :body, class: "form-control", rows: 3 %>
  </div>

  <% if current_user == @availability.user %>
    <div class="form-group d-flex justify-content-end">
    <%= f.button 'Description<i class="fas fa-paper-plane"></i>'.html_safe, type: :submit, class: "btn btn-primary" %>
  </div>
  <% else %>
    <div class="form-group d-flex justify-content-end">
    <%= f.button 'Comment<i class="fas fa-paper-plane"></i>'.html_safe, type: :submit, class: "btn btn-primary" %>
  </div>
  <% end %>
  <% end %>
  </div>
    
    <div class="col-md-4">
      <div class="dropdown">
          <a class="btn btn-secondary dropdown-toggle" href="#" role="button" id="dropdownMenuLink" data-bs-toggle="dropdown" aria-expanded="false">
            <i class="fas fa-cog"></i>
          </a>

          <ul class="dropdown-menu" aria-labelledby="dropdownMenuLink">
            <li><%= link_to "Edit this availability", edit_availability_path(@availability), class: 'dropdown-item' %></li>
            <li><%= button_to "Destroy this availability", @availability, method: :delete, class: 'dropdown-item', data: { confirm: 'Are you sure?' } %></li>
          </ul>
      </div>
    </div>
  </div>
</div>
```

## Next Steps
Now that I have a calendar to display the index of availabilities, I will develop a calendar with filtering for availabilities where the user is a the event creator and availabilities where the user is a guest. I will also implement a dashboard for guest status.