palash-kulkarni
palash-kulkarni

Reputation: 407

Write ActiveRecord Query

I am having Orders with status(Pending, and Completed), Pickup_date, dropoff_date. And i want to order conditionally on the basis of status.

Upvotes: 1

Views: 62

Answers (4)

Peter Toth
Peter Toth

Reputation: 1004

I would highly recommend not to mix scope responsibilities. If you do it all in one scope called order_by_time, the naming is confusing, if I see Order.order_by_time I will assume that it only orders the result, and I will be truly surprised when I learn the reality after checking the implementation...

I would recommend some isolation, which provides more flexibility for later use:

scope :pending,   -> { where(status: :pending) }
scope :completed, -> { where(status: :completed) }

scope :order_by_pickup_time, -> { order(pickup_time: :desc) }
scope :order_by_dropof_time, -> { order(dropof_time: :desc) }

Then you could use them:

Order.pending.order_by_pickup_time
Order.completed.order_by_dropof_time

Upvotes: 1

palash-kulkarni
palash-kulkarni

Reputation: 407

We can do it in single query in scope as :

scope :order_by_time, -> { order("CASE WHEN (orders.state IN ('pending', 'picked_up')) THEN 'orders.pick_up_time' WHEN (orders.state IN ('ready_for_delivery', 'delivered')) THEN 'orders.delivery_time' END") }

Upvotes: 1

fabOnReact
fabOnReact

Reputation: 5942

Query using conditionals

I suggest to use conditionals query

class Orders < ApplicationRecord
  scope :order_by_pickup_time, ->(status) { where("created_at < ?", pickup_time) if status == "pending" }
end

Like the other examples, this will behave similarly to a class method.

class Orders < ApplicationRecord
  def self.order_by_pickup_time(status)
    where("created_at < ?", pickup_time) if status == "pending"
  end
end

However, there is one important caveat: A scope will always return an ActiveRecord::Relation object, even if the conditional evaluates to false, whereas a class method, will return nil. This can cause NoMethodError when chaining class methods with conditionals, if any of the conditionals return false.

Upvotes: 0

Rajarshi Das
Rajarshi Das

Reputation: 12320

In the model

  scope :pending, -> { where(status: "pending").order(pickup_time: :desc) }
  scope :completed, -> { where(status: "completed").order(dropof_time: :desc) }

Then use Order.pending it will order by pick up time it with all pending orders Then use Order.completed it will order it with all conmpleted orders by dropoff time

Upvotes: 0

Related Questions