【问题标题】:How to combine scopes in Ruby on Rails 3?如何在 Ruby on Rails 3 中组合范围?
【发布时间】:2012-03-15 19:31:10
【问题描述】:

我对 Rails 很陌生,我似乎无法理解这一点:

我有不同的项目属于不同的客户

在我的 Project 模型中,我有两个搜索功能:

scope :search_by_name, lambda { |fn| where('name LIKE ?', "%#{fn}%") }

scope :search_by_client, lambda { |fn| where('client_id LIKE ?', fn) }

两者似乎都有效。例如在 URL 中我可以在这个查询中传递:

/projects?search_by_name=fooproject

我同样可以这样做:

/projects?search_by_client_name=misterx

这将产生属于 Client MisterX 的所有 Projects

现在有没有办法结合这两个搜索功能,以便查询

/projects?search=foofoo

将检索名为 foofoo 的项目以及属于名为 foofoo 的客户的项目?

感谢您的帮助!

【问题讨论】:

  • 你的控制器是什么样子的?
  • 像这样:@projects = current_user.projects.search_by_name(params[:name]).search_by_client(params[:client])

标签: ruby-on-rails ruby search scope


【解决方案1】:

在 SQL 中,您可以按多个条件进行搜索。您已经定义了两个作用域,它们可以链接在一起,如下所示:

Project.search_by_name('fooproject').search_by_client('misterx')

这将创建以下 SQL:

SELECT "projects".* FROM "projects" WHERE "projects".name LIKE '%fooproject%' AND "projects".client_id LIKE '%misterx'

连接这两个条件的运算符是“AND”,这意味着结果将是同时满足这两个条件的那些,而不是任何一个条件。

有几种方法可以检索具有特定名称的项目或属于客户的项目。最简单的方法是创建一个指定 OR 运算符的新范围:

scope :search_by_name_or_client, lambda { |name, client| where('name LIKE ? OR client_id LIKE ?', "%#{name}%", "%#{client}%") }

您可能还想查看 SQL UNION,它结合了两个或多个 select 语句的结果集。 ActiveRecord 不处理 UNION 功能,但有一些 gem 可以扩展功能以包含此功能,例如 https://github.com/tsmango/union

使用 Union gem 编写此代码的示例如下所示:

Project.union([{:conditions => ['name like ?', "%#{name}%"]}, {:conditions => ['client like ?', "%#{client}%"]}])

这将生成以下 SQL:

SELECT "projects".* FROM "projects" WHERE "projects".name LIKE '%fooproject%'
UNION
SELECT "projects".* FROM "projects" WHERE "projects".client_id LIKE '%misterx'

更多关于 SQL UNION 的信息可以在这里找到:http://www.w3schools.com/sql/sql_union.asp

【讨论】:

  • 嗨,本,感谢您的帮助。你能告诉我如何在我的控制器中使用这个功能吗?现在我有这个,但我不能让它工作:@projects = current_user.projects.search_by_name_or_client(params[:name], params[:client])
  • 您将在您的项目类中定义一个看起来像这样的范围:scope :search_by_name_or_client, lambda {|name, client_id| where("name like ? OR client_id like ?", "%#{name}%", "%#{client_id}")
  • 在您的问题中,您似乎正在搜索 client_name,但正在检查 client_id 列。我不确定您要搜索哪个字段。 client_id 可能是您的项目表中的一列,这意味着您无需加入客户端即可按名称搜索。如果客户端是关联数据,您的范围可能如下所示:scope :search_by_name_or_client, lambda {|name, client_name| where("name like ? OR clients.name like ?", "%#{name}%", "%#{client_name}").joins(:client)
  • 好的,现在工作好多了。非常感谢!遗憾的是,在控制器中链接这些方法将通过AND 而不是OR 连接它们...
  • 这在某种程度上是有道理的,因为 OR 依赖于两个或多个条件,并且无法表示分组。 AND 很容易,因为您可以将这些条件添加到查询的末尾。这回答了你的问题了吗?如果是这样,您介意将其标记为已接受的答案吗?
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-03-31
  • 2016-04-03
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多