When building an Airbnb clone app, we often have a booking
model in our application.(And hopefully you have a default status.). It should look something like this:
Really the only thing we're interested here is how to change the status to accepted
or rejected
as the owner of the offer. An AirBnb host isn't going to accept every offer that comes through. So how does this work? Do we create buttons? Links? Separate controller actions for accept and reject? No. I've seen a lot of different ways people try to solve this, but it's best to keep it simple.
We need a form. This form is just going to update
our booking. This allows our bookings#update
controller action to handle both the accepting and rejecting.
Setup the Route
Let's make sure we have the correct route in our routes.rb
. This shouldn't be nested since the bookings already have an ID.
# routes.rb
resources :bookings, only: [:update]
Configure the Controller
Let's add the update action in the bookings
controller (along with the strong params if they're missing). This is just standard CRUD, nothing special here.
# bookings_controller.rb
def update
@booking = Booking.find(params[:id])
if @booking.update(booking_params)
# redirect_to # up to you...
else
# render # where was the booking update form?
end
end
private
def booking_params
# TODO: check your model, might be different than mine
params.require(:booking).permit(:status, :start_time, :end_time)
end
Build your View
Now to the tough part. Let's go to your view where you want to accept and reject. This can be a couple places depending on how you build your routes.
I'm going to make another assumption here. You're either iterating over @bookings
or something like current_user.bookings_as_owner
.
<% @bookings.each do |booking| %>
<!-- with the booking card here -->
<% end %>
You can design your cards how you see it fit with your application. But I'll let's just use a simple one to get started.
Okay now for those "buttons". We don't want just a normal button or link though. This is where we need the booking update form. Let's use simple_form_for (check out the docs here).
We're going to need two forms for each action. And we're going to hide the new status as a hidden field. The "button" is going to be the submit for the form. Like this:
<div class="d-flex">
<%= simple_form_for booking do |f| %>
<%= f.input :status, as: :hidden, input_html: { value: 'accepted'} %>
<%= f.submit 'Accept', class: 'btn btn-info' %>
<% end %>
<%= simple_form_for booking do |f| %>
<%= f.input :status, as: :hidden, input_html: { value: 'rejected'} %>
<%= f.submit 'Reject', class: 'btn btn-light' %>
<% end %>
</div>
Status Conditional
If your booking status is pending
then we'll show the forms. Otherwise, we'll display the status.
Let's create a method in our model.
⚠️ If you are using status as an enum
, you don't need this. You already have this method available.
# booking.rb (model)
def pending?
status == 'pending'
end
Now we can use that method in our conditional
<% if booking.pending? %>
<!-- Display Forms-->
<% else %>
<!-- Display Status-->
<p class='booking-tag'><%= booking.status %></p>
<% end %>
We should get some bookings like this now:
Wrap Up
Now all we have to do is build these forms in our iteration.
ERB
<div class="bookings">
<% @bookings.each do |booking| %>
<div class="booking">
<div class='booking-left'>
<!-- if you're using cloudinary and activestorage -->
<%= cl_image_tag booking.user.photo, class: 'avatar-bordered' %>
<div class="booking-info">
<div class="booking-info-title">
<%= booking.user.name %>
</div>
<div class="booking-info-details">
<%= booking.start_time.strftime('%l:%M %p') %> - <%= booking.end_time.strftime('%l:%M %p') %>
</div>
</div>
</div>
<div class="booking-actions">
<% if booking.pending? %>
<%= simple_form_for booking do |f| %>
<%= f.input :status, as: :hidden, input_html: { value: 'accepted'} %>
<%= f.submit 'Accept', class: 'btn btn-info' %>
<% end %>
<%= simple_form_for booking do |f| %>
<%= f.input :status, as: :hidden, input_html: { value: 'rejected'} %>
<%= f.submit 'Reject', class: 'btn btn-light' %>
<% end %>
<% else %>
<p class='booking-tag'><%= booking.status %></p>
<% end %>
</div>
</div>
<% end %>
</div>
CSS
.booking {
display: flex;
justify-content: space-between;
align-items: center;
margin: 16px 0;
.booking-left {
display: flex;
align-items: center;
}
.booking-actions {
display: flex;
align-items: center;
}
.booking-tag {
margin: 1px 4px;
padding: 2px 5px 0px 5px;
background-color: #bfbfbf;
color: white;
border-radius: 8px;
font-weight: lighter;
font-size: 12px;
}
}
.booking-info {
display: flex;
flex-direction: column;
margin-left: 8px;
.booking-info-title {
font-weight: bolder;
font-size: 1.2em;
}
.booking-info-details {
font-weight: lighter;
}
}
Top comments (0)