如何将arel对象合并到ActiveRecord :: Relation链中?

时间:2013-05-31 14:12:43

标签: ruby-on-rails ruby-on-rails-3 activerecord arel activerecord-relation

我知道如何将以下内容转换为使用严格的Arel方法,而不是混合的sql / string,但我不知道如何将生成的arel对象合并到ActiveRecord :: Relation中,这样我就可以链接更多的AR :: Relation方法就可以了。

我对上一个问题得到了以下非常有用的答案:

class Address < ActiveRecord::Base
  scope :anywhere, lambda{|search|
    attrs = [:line1, :line2, :city, :state, :zip]
    where(attrs.map{|attr| 
      "addresses.#{attr} LIKE :search"
    }.join(' OR '), search: "#{search}%").order(*attrs) 
  }
end

Person.joins(:address).merge(Address.anywhere(query_term))

我试着这样做:

class Address < ActiveRecord::Base
  scope :anywhere, lambda{|search|
    addr_arel = Address.arel_table
    attrs = [:line1, :line2, :city, :state, :zip]
    attrs.inject {|attr| 
      q = addr_arel[attr].match("%#{search}%") unless q
      q = q.or(addr_arel[attr].match("%#{search}%")
    }
  }
end

但我最终得到一个arel对象,我不知道如何将它与以下ActiveRecord :: Relation合并:

Person.joins(:地址).merge(Address.anywhere(QUERY_TERM))

(更不用说注射也不是很优雅 - 我该如何改进呢?)

1 个答案:

答案 0 :(得分:2)

ActiveRecord :: Relation.where接受ARel谓词,因此在这种情况下,您可以直接将最终谓词传递给Address.where。

class Address < ActiveRecord::Base
  scope :anywhere, -> search {
    addr_arel = Address.arel_table
    attrs = [:line1, :line2, :city, :state, :zip]

    where attrs
      .map {|attr| addr_arel[attr].matches("%#{search}%")}
      .inject(:or)
  }
end