joni
joni

Reputation: 5462

Elegant way so access a `belongs_to` -> `has_many` relationship

In my app, an user belongs_to a customer, and a customer has_many construction_sites. So when I want to show the current_user only his construction_sites, I have multiple possibilities of which none is elegant:

@construction_sites = ConstructionSite.where(customer: current_user.customer)

This works and looks good, except for the case that the user is not yet associated with a customer. Then, I get a PG::UndefinedColumn: ERROR: column construction_sites.customer does not exist error.

@construction_sites = ConstructionSite.where(customer_id: current_user.customer_id)

This seems to work fine on first sight, but again for the case that the user is not yet associated with a customer current_user.customer_id is nil and ConstructionSite.where(customer_id: nil) gets called which selects all (or all unassigned?) sites, which is not what I want.

unless...

unless current_user.customer.nil?
  @construction_sites = ConstructionSite.where(customer: current_user.customer)
else
  @construction_sites = []
end

Well this works, but does not look nice.

ConstructionSite.joins(customer: :users).where('users.id' => current_user.id)

works but does not look nice.

So, what is the most elegant solution to this problem?

Upvotes: 0

Views: 94

Answers (3)

Super Engineer
Super Engineer

Reputation: 1976

Try using delegate keyword. Add this to your user model.

delegate :construction_sites, to: :customer, allow_nil: true

After that you can use statements like

current_user.construction_sites

Which I find the most elegant of all options.

Upvotes: 2

Paul Fioravanti
Paul Fioravanti

Reputation: 16793

How about moving your logic to a named scope and putting in a guard clause?

class SomeController < ApplicationController
  def some_action
    @construction_sites = ConstructionSite.for(current_user)
  end
end

class ConstructionSite < ActiveRecord::Base
  def self.for(user)
    return [] if user.customer.blank?
    where(customer: user.customer)
  end
end

Upvotes: 0

Brandon Hansen
Brandon Hansen

Reputation: 205

def user_construction_sites
  @construction_sites = []
  @construction_sites = current_user.customer.construction_sites if current_user.customer.present?
  @construction_sites
end

Upvotes: 0

Related Questions