I am trying to filter results by age using ransack, but ransack is giving me an undefined method error. I have the Users DOB in my database and in my users model I have an age method that calculates the age of the user. It works perfectly fine and I am able to call the users age like this:
@user = User.find(1)
@user.age
Now for ransack I have the following in my controller:
def index
@search = User.search(params[:q])
@users = @search.result
end
In my view, I have:
<%= search_form_for @search do |f| %>
<%= f.label :age_gteq, "Ages:" %> <%= f.text_field :age_gteq %>
<%= f.label :age_lteq, "to" %> <%= f.text_field :age_lteq %>
<%=f.submit "Filter", class: "button" %>
<% end %>
This is the error I am getting:
undefined method `age_gteq' for Ransack::Search<class: User, base: Grouping <combinator: and>>:Ransack::Search
I am sure I'd get the same error for age_lteq
As far as I know it doesn't work, because currently Ransack only works with database columns. In the end Ransack is just a sophisticated SQL query generator.
Think about this example:
User.where('age >= ?', 30)
What would a SQL query look like?
SELECT * FROM user WHERE age >= 30
Even if Ransack would pipe through such conditions on normal non-database attributes, the SQL would still be wrong. (Since there is no age
column)
One solution would be to use the original date-of-birth column in your form and use some Javascript to allow the user to enter age numbers instead of dates. For example by listening to the onsubmit
event and modify the input
's content.
Update 2014-01-08:
There is another possibility to make this work. Add this to your User
model:
ransacker :age do
Arel::Nodes::SqlLiteral.new(
'DATE_PART('year', AGE(NOW(), date_of_birth_column))')
# Beware: PostgreSQL specific SQL!
end
A "ransacker" needs to return an Arel node which later will be attached to the Arel nodes generated by Ransack.
This allows you to use age_eq
and all the other Ransack predicates just as it were a regular database column.