Assemble a complex SQL query using Activerecord::Relation and/or Arel with 'joins', 'as', and 'like'

StackOverflow https://stackoverflow.com/questions/16827467

Вопрос

I am building a rails 3.2 app using datatables (http://datatables.net) with client-side paging and filtering on most html tables and server-side paging and filtering on some other html tables. I want to do per-column filtering, which is super-easy for the client side tables, but I think I need to construct a sql query for the database to do per-column filtering for the server side tables. I closely followed the example from RailsCast #340 on datatables and got that working.

The challenge is doing sorting and filtering on a column that is really a foreign_key relation to another table. I don't want to sort and filter on the actual contents of the foreign_key values. I want to sort and filter on the '.to_s' values displayed for the linked objects (which is the semantics of using the client-side sort and filter feature). Here is an example:

class Address < ActiveRecord::Base
  attr_accessible :city, :line1, :line2, :state, :zip

  has_many :people

  def to_s
    [line1, line2, city, state, zip].join(' ')
  end
end
class Person < ActiveRecord::Base
  attr_accessible :address, :name

  belongs_to :address
end

so the view displaying the people list has two columns, for name and address

<td><%= p.name %></td>
<td><%= p.address %></td>

and what appears in the index table is

John Smith |  1234 Main St Anywhere City AA 12345

so with client-side sorting and filtering I can search for 'Anywhere' in the address column and get all the rows with that term in the address field. Doing the same thing on the server-side seems much more difficult. I think I'm trying to assemble a sql query that looks something like:

select * from people 
         join address on people.address_id = address.id
        where concat(address.line1, 
                     address.line2, 
                     address.city, 
                     address.state, 
                     address.zip) as spec_address like query_term 
     order by spec_address

(This is not necessarily correct SQL code.)

I've looked at both the ActiveRecord Query Rails guide and anything I could find on Arel without success.

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

Решение

You can do this with a scope on Address which is then merged into the Person query.

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))
Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top