我的应用程序有一个Job模型。系统中的每项工作都有一个contact
。这就像一个人,如果你需要问一个关于这个工作的问题,你会打电话给你。联系人可以是client
或客户的雇员(ClientEmployee
)。连接ActiveRecord ::通过多态关联查询
class Job < ActiveRecord::Base
belongs_to :contact, polymorphic: true
end
class Client < ActiveRecord::Base
has_many :jobs, as: :contact
has_many :employees, class_name: 'ClientEmployee'
end
class ClientEmployee < ActiveRecord::Base
belongs_to :client
has_many :jobs, as: :contact
end
客户有想法commissioned_jobs
。客户委托的工作是那些客户是联系人的工作,或者客户的其中一名雇员是联系人。
class Client < ActiveRecord::Base
has_many :jobs, as: :contact
has_many :employee_jobs, through: :employees, source: :jobs
def commissioned_jobs
jobs << employee_jobs
end
end
除了:该方法是一个黑客位的,因为它返回一个数组,而不是一个ActiveRecord::Relation
。如果我尝试将职位连接到employee_jobs,这也很有趣。它可能会或可能不会为我的目的。
我想添加一个范围Client
叫with_commissioned_jobs
。这应该返回系统中所有有工作或有雇员有工作的客户。
class Client < ActiveRecord::Base
def self.with_commissioned_jobs
# I can get clients with jobs using: joins(:jobs). How do
# I also include clients with employees who have jobs?
end
end
如何实现此方法?
我正在使用Rails 3.2.9。
更新:
我已经取得了一些进展,我现在有两种方法,每个做什么,我需要的一半。
class Client < ActiveRecord::Base
# Return all clients who have an employee with at least one job.
def self.with_employee_jobs
joins(employees: :jobs)
# SQL: SELECT "clients".* FROM "clients" INNER JOIN "client_employees" ON "client_employees"."employer_id" = "clients"."id" INNER JOIN "jobs" ON "jobs"."contact_id" = "client_employees"."id" AND "jobs"."contact_type" = 'ClientEmployee'
end
# Return all clients who have at least one job.
def self.with_jobs
joins(:jobs)
# SQL: SELECT "clients".* FROM "clients" INNER JOIN "jobs" ON "jobs"."contact_id" = "clients"."id" AND "jobs"."contact_type" = 'Client'
end
end
现在我需要做的就是将这两个方法调用合并为一个ActiveRecord::Relation
。我可以明显地做到这一点:
def self.with_commissioned_jobs
with_jobs + with_employee_jobs
end
的问题是,它返回一个数组而不是Relation
一个实例,我不能链子更范围。
更新2:
使用merge
似乎并没有擦出火花。这是AR查询和生成的SQL。
joins(:jobs).merge(joins(employees: :jobs))
SELECT "clients".* FROM "clients" INNER JOIN "jobs"
ON "jobs"."contact_id" = "clients"."id"
AND "jobs"."contact_type" = 'Client'
INNER JOIN "client_employees"
ON "client_employees"."employer_id" = "clients"."id"
INNER JOIN "jobs" "jobs_client_employees"
ON "jobs_client_employees"."contact_id" = "client_employees"."id"
AND "jobs_client_employees"."contact_type" = 'ClientEmployee'
顺便说一下,这里是我试图通过的测试。第一次测试失败,因为使用合并时结果为零。
describe "with_commissioned_jobs" do
# A client with a job.
let!(:client_with) { create :client }
let!(:job) { create :job, contact: client_with }
# A client who does not himself have a job, but who has an employee
# with a job.
let!(:client_with_emp) { create :client }
let!(:employee) { create :client_employee, employer: client_with_emp }
let!(:emp_job) { create :job, contact: employee }
# A client with nothing. Should not show up.
let!(:client_without) { create :client }
it "should return clients with jobs and clients with employee jobs" do
Client.with_commissioned_jobs.should == [client_with, client_with_emp]
end
it "should return a relation" do
Client.with_commissioned_jobs.should be_instance_of(ActiveRecord::Relation)
end
end
你看过arel吗? https://github.com/rails/arel它具有查询条件或条件,并可以很好地处理复杂的联接。 – John
我当然也会接受一个基于Arel的解决方案。我花了好几个小时试图想出一个,我似乎无法管理它。 –