Can't make complex SQL request in rails

Viewed 77

I have two separate models MarketOrder and OnlineOrder.

Two models do not have any relationship between them but need to be displayed in one table.

Sorting and Pagination required. Simple solution would be:

orders = (MarketOrder.all + OnlineOrder.all).sort_by(&:created_at).paginate(per_page: 50, page: params[:page])

This works fine but it is not suitable as number of orders constantly grows. Query all records would cause a huge drop in performance. How correctly to narrow such query? Thanks

Update

Models do not have exactly the same columns but share some common ones which need to be displayed in my view file.

MarketOrder(
  id: integer, 
  user_id: integer, 
  service_fee_amount: decimal, 
  status: string, price: decimal, 
  created_at: datetime, 
  updated_at: datetime..
)
OnlineOrder(
  id: integer, 
  user_id: integer, 
  category: string, 
  comment: text, 
  status: string, 
  price: decimal, 
  created_at: datetime, 
  updated_at: datetime...
)

Please note that both models are independent and Ids in both go 1,2,3... 1,2,3...

But each model has a relation with a third model User (belongs_to <=> has_many) and where each table contains user_id.

as per sort_by(&:created_at).paginate(per_page: 50, page: params[:page]) 50 most recent orders would be prepared with jbuilder and send to react component. To get next 50 orders the request would be made again to backend.

1 Answers

You could create a polymorphic table Order, should have fields order_link_type (string), order_link_id (integer) and order_created_at (datetime)

class Order < ApplicationRecord
  belongs_to :order_link, polymorphic: true, optional: true
end

class MarketOrder < ApplicationRecord
  has_one :order, as: :order_link, dependent: :destroy
  after_save :create_order
  private
  def create_order
    return if order

    build_order(order_created_at: created_at)
  end
end


class OnlineOrder < ApplicationRecord
  has_one :order, as: :order_link, dependent: :destroy
  after_save :create_order
  private
  def create_order
    return if order

    build_order(order_created_at: created_at)
  end
end

and now you can do...

orders = Order.all.sort_by(&:order_created_at).paginate(per_page: 50, page: params[:page])

You can access the fields in your view as order.order_link.user_id and for the fields that only exist on one type or order link you can conditionally retrieve the value, like order.order_link.try(:comment) You may want to delegate to the Order class some of the fields so you can just reference order.user_id

Related