Arel Relation引用has_many关系

时间:2013-11-10 22:30:41

标签: ruby-on-rails ruby activerecord arel

我有一个基本的has_many关系,模仿如下:

class Term < ActiveRecord::Base
    has_many :acroynms
end

class Acronym < ActiveRecord::Base
    belongs_to :term    
end

我想写一个arel关系,它将根据术语的名称或首字母缩略词的名称来提取术语。我的关系是不正确的,但我希望做一些看起来像这样的事情:

terms = Term.arel_table
relation = terms[name].matches("%#{params['a']}%")
relation = relation.or(terms[:acronyms.name].matches("%#{params['a']}%"))
@results = Term.where(relation)

我想将它保留在关系中,因为我将许多其他组合条件组合到一个关系中(为简洁起见,我在此省略)。

我正在使用这种关系,而不是仅仅在最后一行上将所有内容组合在一起就是需要编写的项目在运行时才会知道,具体取决于用户输入。我的想法是使用这个模型我将能够设置我的关系,无论它有多复杂,然后只需要一行来设置@results,无论用户输入如何。

有没有办法在关系中写出这一切?否则,我想我需要求助于使用arel的连接,但只有在用户输入调用它的情况下才加入,是否正确?

2 个答案:

答案 0 :(得分:1)

我不完全确定如何使用arel执行此操作,但如果您希望基于参数(或其他输入)将where子句链接到构建后执行,则可以执行此类操作:

query = User.scoped

query = query.where("name like ?", "%#{params[:name]}%") if params[:name].present?
query = query.where("email like ?", "%#{params[:email]}%") if params[:email].present?

@users = query.all

同样,我知道这不是你想要的,但可能是一种可能的选择。

注意:如果您在控制台中运行它,这将无法达到预期效果,因为REPL的print步将执行每一步,使其在进入时看起来像多个查询一个Rails应用程序,它实际上只执行一个。

答案 1 :(得分:0)

为了绕过使用OR运算符,我通过使用3个查询解决了这个问题,这些查询是次优的,但功能正常。

我的第一个查询查找名称与搜索参数类似的首字母缩略词。

acronymQuery = query.includes(:acronyms).where('acronyms.name like ?', wildcard_search).select("terms.id")

第二个查找名称与搜索参数类似的术语。

termQuery = query.where('terms.name like ?', wildcard_search).select("terms.id")

然后我合并了每个查询的唯一ID,我的第三个查询会搜索这些ID。

acronymQueryResults = acronymQuery.all.map {|row| row.id}
termQueryResults = termQuery.all.map {|row| row.id}
ids = (acronymQueryResults + termQueryResults).uniq
query = Term.where('id' => ids)