Reputation: 59
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.
Upvotes: 1
Views: 623
Reputation: 35531
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))
Upvotes: 1