Search code examples
ruby-on-railsrubygemsruby-on-rails-7

How to proceed accept and reject feature with rails


I'm trying a feature where user can request for offer and it can be accepted or rejected , I'm new to rails. i can't figure out what's the good way to proceed this. offer create method

def create
@offer = Offer.new(offer_params)
pp offer_params
@barter = Barter.find(params[:barter_id])
@offer = Offer.new(offer_params)
@offer.barter = @barter
@offer.user = current_user
respond_to do |format|
  if @offer.save
    format.js do
      @barter = Barter.find(params[:barter_id])
    end
  else
    format.html { render :new, status: :unprocessable_entity }
    format.json { render json: @review.errors, status: :unprocessable_entity }
  end
end

end

offer submission

  <%= form_for([ @barter, @barter.offers.new] ) do |form| %>

            <%= form.text_area :message %><br>
            <%= form.submit "leave" %>

      <% end %>

here I want to make it accepted or rejected , I've given a boolean value and simply make it false when rejected

  <%= form_tag([ @barter, @barter.offers.new] ) do  %>

            <%= hidden_field_tag :reject, :value => true %><br>
            <%= submit_tag "reject" %>

          <% end %>

is there a good way to do this? and how can i make it disappear when i accept this.


Solution

  • Sorry but thats not even close. You're just creating a new offer record in the form when what you should be doing is to update an existing record - and while you potentially do this through PATCH /offers/:id its going to be very ambigeuos in terms of intent.

    The simplest way I cn think of handle this would be to simply add two additional RESTful routes to update the offers.

    Start by adding the routes:

    resources :offers, only: [] do
      patch :accept
      patch :decline
    end
    

    And en enum attribute to the model:

    class AddStatusToOffers < ActiveRecord::Migration[7.0]
      def change
        add_column :offers, :status, :integer, default: 0, index: true
      end
    end
    
    class Offer < ApplicationRecord
      # ...
      enum status: {
        pending: 0,
        accepted: 1,
        rejected: 2
      }
    end
    

    This is a better idea then adding a boolean since your boolean would either need to be a tri-state boolean (nullable) which is regarded as a very bad practice or default to false in which case you can't differentiate between the offers a users has replied to or not.

    Then add the controller methods for your new endpoints:

    class OffersController
      before_action :set_coffer, only: %i{ show edit update destroy accept decline }
    
      # ...
    
      # PATCH /offers/:id/accept
      # @TODO authorize that the user should actually be allowed the offer
      def accept
        if @offer.accepted!
          redirect_to @offer, notice: 'Offer accepted'
        else
          redirect_to @offer, notice: 'Offer could not be accepted - please try again' 
        end
      end
    
      # PATCH /offers/:id/reject
      # @TODO authorize that the user should actually be reject the offer
      def reject
        if @offer.rejected!
          redirect_to @offer, notice: 'Offer rejected'
        else
          redirect_to @offer, notice: 'Offer could not be rejected - please try again' 
        end
      end
    
      private
    
      def set_offer
        @offer = Offer.find(params[:id])
      end
    end
    

    You can then simply add buttons/links that send the request to update the offer:

    <%= button_to "Accept", accept_offer_path(offer), method: :patch %> 
    <%= button_to "Reject", reject_offer_path(offer), method: :patch %> 
    

    This is not the only way to solve the issue. If you for example want to record a message where the user can say why they rejected an offer I would model replies to an offer as a completely seperate resource.