优雅的方式所以访问`belongs_to` - > `has_many`关系

时间:2014-04-03 06:24:26

标签: ruby-on-rails ruby postgresql activerecord ruby-on-rails-4

在我的应用中,用户belongs_to是客户,客户是has_many construction_sites。因此,当我想仅显示current_user construction_sites时,我有多种可能性,其中没有一种是优雅的:

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

除了用户尚未与客户关联的情况外,这种方法效果很好。然后,我收到PG::UndefinedColumn: ERROR: column construction_sites.customer does not exist错误。

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

这似乎在第一眼就能正常工作,但对于用户尚未与客户current_user.customer_id关联的情况,nilConstructionSite.where(customer_id: nil)会被调用,这会选择所有(或者所有未分配的网站,这不是我想要的。

unless...

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

这很有效,但看起来不太好。

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

有效,但看起来不太好。

那么,这个问题最优雅的解决方案是什么?

3 个答案:

答案 0 :(得分:2)

尝试使用delegate关键字。将其添加到您的用户模型。

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

之后您可以使用

之类的语句
current_user.construction_sites

我发现所有选项中最优雅的。

答案 1 :(得分:0)

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

答案 2 :(得分:0)

如何将逻辑移动到命名范围并插入保护条款?

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