我希望仅使用命名范围来编写此查询。原因很简单,当我改变Client
被认为活跃的方式时,我不想在任何地方更改代码(User
认为可连接相同)
这是我的代码
client.rb
class Client < ActiveRecord::Base
has_one :user
scope :actives, -> { where(starting_date: a_date, finishing_date: another_date, enabled: true) }
end
user.rb
class User < ActiveRecord::Base
belongs_to :client
scope :connectable, -> { where.not(access_token: nil, instance_url: nil) }
end
在这里你可以找到我写这个查询的尝试:
# What I would like to write
User.eager_load(:client).connectable.where("client is in :actives scope")
# Current options
# 1 - (but this violates dry)
User.eager_load(:client).connectable.where(['clients.starting_date = ? AND clients.finishing_date = ? AND clients.enabled = ?', a_date, another_date, true).references(:client)
# 2 - My best attempt so far
User.connectable.where(client_id: Client.actives.pluck(:id))
指向GIST的链接
答案 0 :(得分:1)
您正在寻找的是ARel的merge
方法。 (An article on this here.)
试试这个:
User.connectable.includes(:client).merge(Client.actives).references(:clients)
includes(:client)
将介绍来自User的客户关系,这将使.merge(Client...)
范围有效。并且Rails 4+要求.references
明确说明includes
语句将引用哪个表。
答案 1 :(得分:0)
我不确定它有多好,但只要您确保列名称的名称间距正确(即,您不能拥有&#39; foo&#39; in客户端和用户都没有前缀表名称)然后这应该工作:
User.eager_load(:client).connectable.where(Client.active.where_values.map(&amp;:to_sql).join(&#34; AND&#34;))
必须有一个更好的方式,但上述方法对我有用:
课程模式:
scope :valid, -> { enabled.has_country }
scope :has_country, -> { where.not(country_id:nil) }
Rails控制台:
> Course.where(Course.valid.where_values.map(&:to_sql).join(" AND ")).to_sql
=> "SELECT \"courses\".* FROM \"courses\"
WHERE (\"courses\".\"is_enabled\" = 't'
AND \"courses\".\"country_id\" IS NOT NULL)"