At Le Wagon, our students spend 1 week building a Ruby on Rails Airbnb clone. We normally end up with a schema relatively close to this:
When we get to the bookings page, it can be tricky how to retrieve all of the relevant bookings for a particular user. An empty bookings page example (with tabs)
If we use Booking.all
, this will give us all of the bookings for every user in the entire application which is obviously not what we want. The simple version of this would just to get all of the bookings for the person logged in (if you're using Devise) current_user.bookings
However, you may have noticed that on our booking
, we have a start_date
, end_date
, and status
. So our bookings become a little bit more complicated. Do we want all of our pending
bookings? Bookings that are in the future? Bookings that are currently happening? Well when we use current_user.bookings
, it's giving us everything.
To be able to sort through all the different types of bookings that we have, we can use Active Record scopes. If you haven't dealt with scopes before, the syntax might feel a bit strange. Here is one example:
# booking.rb (model)
scope :past, -> { where('end_date < ?', Date.today) }
This gives us access to method .past
now. So in our controller, we could use Booking.past
if we want past bookings from all users. But in this particular example, now we can access all the past bookings for a particular user: current_user.bookings.past
So given this one example of a scope, we could now go crazy with lot of different types of bookings (depending on how we're using them in the view). Our model might end up looks like this:
class Booking < ApplicationRecord
belongs_to :user
belongs_to :offer
validates :start_date, presence: true
validates :end_date, presence: true
enum status: { pending: 0, accepted: 1, rejected: 2 }
scope :past, -> { where('end_date < ?', Date.today) }
scope :future, -> { where('start_date > ?', Date.today) }
scope :active, -> { where('start_date < ? AND end_date > ?', Date.today, Date.today) }
scope :today, -> { accepted.where(date: Date.today) }
scope :upcoming, -> { accepted.future }
scope :need_response, -> { pending.future }
scope :expired, -> { pending.past }
scope :completed, -> { accepted.past }
scope :not_rejected, -> { where.not(status: :rejected) }
def number_of_days
(start_date - end_date).to_i
end
def price
offer.price * number_of_days
end
end
Now thinking about our how to use this, we can load all of the user's bookings in the bookings controller.
def index
@bookings = current_user.bookings
end
Then in our view we can display whatever type of bookings that we decided, using our newly made scopes!
<%= render 'cards', bookings: @bookings.today %>
<%= render 'cards', bookings: @bookings.future %>
<%= render 'cards', bookings: @bookings.active %>
<%= render 'cards', bookings: @bookings.need_response %>
<%= render 'cards', bookings: @bookings.past %>
<!-- etc. -->
Top comments (0)