Hommer Smith
Hommer Smith

Reputation: 27852

Unify two queries for current_user in Rails

I have the following associations:

A User has_many Hosts and a Host has_many Orders

I have nested routes for Hosts and Orders, so when a user wants to see Orders, it will have to be through a Host (/hosts/:id/orders)

I want to avoid users accessing other users orders, so I have this in my index action:

def index
  host = current_user.hosts.find(params[:host_id])
  redirect_to :back, alert: 'Host was not found' if host.nil?
  orders = host.orders.includes(:order_state).order('id ASC')
end

As you can see I am hitting the DB twice. One to find if the host exists for current_user, and another one to find the orders for this host.

How can I do this in just one query?

Upvotes: 2

Views: 51

Answers (2)

Jiří Pospíšil
Jiří Pospíšil

Reputation: 14402

As already mentioned by sufleR, there probably isn't an easy way how to distinguish between no orders for the given host and host not found. The code, however, can be simpler:

class User < ActiveRecord::Base
  has_many :hosts
  has_many :orders, through: :hosts # !!!
end

orders = current_user.orders.includes(:order_state).order(:id).
  where(host_id: params[:host_id])

Upvotes: 0

sufleR
sufleR

Reputation: 2973

Try something like this:

orders = Order.joins(:host)
              .includes(:order_state)
              .where(hosts: { user_id: current_user.id, id: params[:host_id] })
              .order('orders.id ASC')
redirect_to :back, alert: 'Orders for selected host not found' unless orders.any?

If you want to give user alert for host not found you can't do it with one query.

Upvotes: 1

Related Questions