是否可以仅使用命名范围重写此查询?

时间:2015-01-12 21:07:26

标签: ruby-on-rails ruby-on-rails-4.1

我希望仅使用命名范围来编写此查询。原因很简单,当我改变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的链接

2 个答案:

答案 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)"