Вопрос

I know how to convert the following into using strictly Arel methods, instead of mixed sql/string, but I dont' know how to merge the resulting arel object into an ActiveRecord::Relation so I can chain more AR::Relation methods on it.

I got the following very helpful answer to my previous question:

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))

I tried to do something like this:

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

But I end up with an arel object and I don't know how to merge it with the following ActiveRecord::Relation:

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

(not to mention the inject is not very elegant either - how do I improve that?)

Это было полезно?

Решение

ActiveRecord::Relation.where accepts an ARel predicate, so in this case you can just pass your final predicate directly to 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
Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top