Search code examples
ruby-on-rails-4activerecordnamed-scope

Rails ActiveRecord 4.2 custom sort order


I'm trying to apply a custom scope or class method to the following ActiveRecord model however I'm not sure of the best approach or implementation following Rails best practices.

Please note this is just a simplified example project for explanation purposes.

# event_booking.rb
class EventBooking < ActiveRecord::Base
  has_many :events, -> { order('event_type ASC') }, dependent: :destroy
end

# event.rb
class Event < ActiveRecord::Base
  belongs_to :event_booking
end

# event_bookings_controller.rb
class EventBookingController < ApplicationController
  def show
    @event_booking = EventBooking.find(params[:id])
  end
end

The Event model has an event_type property with 1 of 3 different string values (i.e. morning, afternoon, evening).

The current issue is that the strings are not alphabetical and therefore I cannot use a standard ASC or DESC to order the events collection.

Thus far I have considered making 3 separate queries against the Events model and then combining the results into a single array in a class method. I have also attempted to do something similar to the following with no success.

# event_booking.rb
class EventBooking < ActiveRecord::Base
  has_many :events, -> { order(%w(morning afternoon evenint).map { |cond| where(event_type: "#{cond}") }.join(', ')) }, dependent: :destroy
end

My goal is to have a single ordered events collection accessible from the controller using something similar to @event_booking.events or @event_booking.events_by_type in the following event_type order:

- morning
- afternoon
- evening

The results of the call are being sent as a JSON response to an API call. Currently, this reordering is being done on the client side however I'm trying to render the initial results in the desired order before it is returned to the client.


Solution

  • You can use a sql case statement to control the ordering.

    has_many :events, ->{ "ORDER BY CASE WHEN event_type = 'morning' THEN '1' WHEN event_type = 'afternoon' THEN '2' WHEN event_type = 'evening' THEN '3' END" }