Ransack: использование возраста вместо даты рождения

Я хотел бы использовать ransack для создания функции расширенного поиска для страницы с Users. У меня есть небольшой метод расчета возраста по дате рождения:

def age(dob)
  now = Time.now.utc.to_date
  now.year - dob.year - ((now.month > dob.month || (now.month == dob.month && now.day >= dob.day)) ? 0 : 1)
end

Это работает на обычном дисплее (as in age(@user.date_of_birth))

Но при использовании search_form_for я не могу сделать то же самое:

<%= search_form_for @search, url: search_users_path, method: :post do |f| %>
    <div class="field">
        <%= f.label :date_of_birth_gteq, "Age between" %>
        <%= f.text_field :date_of_birth_gteq %>
        <%= f.label :date_of_birth_gteq, "and" %>
        <%= f.text_field :date_of_birth_lteq %>
    </div>
<div class="actions"><%= f.submit "Search" %></div>
 <% end %>

Мой вопрос: как я могу использовать возраст в моем поиске вместо даты рождения?


person TimmyOnRails    schedule 24.12.2012    source источник


Ответы (3)


Добавьте Scope, как показано ниже, чтобы найти дату для данного возраста.

scope :age_between, lambda{|from_age, to_age|
  if from_age.present? and to_age.present?
    where( :date_of_birth =>  (Date.today - to_age.to_i.year)..(Date.today - from_age.to_i.year) )
  end
}

Для синтаксиса вымогательства:

ransacker :age, :formatter => proc {|v| Date.today - v.to_i.year} do |parent|
  parent.table[:date_of_birth]
end   

Ввиду

<%= f.text_field :age_gteq %>
person siddick    schedule 24.12.2012
comment
Должен ли я использовать это так? ‹%= f.label :age_between_gteq, Возраст между %› ‹%= f.text_field :age_between_gteq %›. Это не сработало. Я получаю эту ошибку: неопределенный метод `age_between_gteq' для Ransack::Search‹class: User, base: Grouping ‹combinator: and››:Ransack::Search - person TimmyOnRails; 24.12.2012
comment
Спасибо! Работает, но не полностью. Для расчета возраста недостаточно года, нужен еще месяц и число, поэтому я не совсем понимаю, как получить эту информацию и использовать ее в рансакере. Так что сейчас эта функция не очень точна, потому что работает только по годам. - person TimmyOnRails; 25.12.2012
comment
Вам не нужно считать месяц или день. Поскольку дата генерируется на основе currency_date - years, она только уменьшает годы и сохраняет текущий день и месяц. - person siddick; 25.12.2012
comment
Вы правы, извините за путаницу. Однако, когда я использую ответ выше, происходят три вещи: - person TimmyOnRails; 25.12.2012
comment
1. Поле _lteq действует как поле _gteq и наоборот (это означает, что вместо 88..92 работает диапазон 92..88). 2. _lteq и _gteq функционируют как _lt и _gt. Например, для диапазона 1..27 приложение не отображает запись 27-летнего человека. 3. Объем, кажется, не имеет никакого эффекта. Когда я отключаю его, он работает так же. Кажется, я нигде не могу найти хороших примеров или объяснений использования такого вымогателя. Спасибо за вашу помощь - person TimmyOnRails; 25.12.2012
comment
@TimmyOnRails У меня та же проблема, что и в комментарии выше. Вам удалось это исправить? спасибо - person randika; 17.01.2013

Я не знаю рансакера лично и пытался использовать рансакер, но не смог найти ничего, что могло бы проверить переданный предикат. Поэтому я считаю, что для этого лучше использовать области видимости.

def self.age_lteq(age)
  start_birth_year = Date.today.year - age
  where('date_of_birth >= ?', Date.new(start_birth_year))
end

def self.age_gteq(age)
  birth_year = Date.today.year - age
  end_of_birth_year = Date.new(birth_year + 1) - 1
  where('date_of_birth <= ?', end_of_birth_year)
end

private

def self.ransackable_scopes(auth_object = nil)
  %i(age_lteq age_gteq)
end

# In views just do the following (ransack default grouping queries is by AND)
# https://github.com/activerecord-hackery/ransack#grouping-queries-by-or-instead-of-and
<%= f.input :age_lteq %>
<%= f.input :age_gteq %>

Ответ @siddick классный, но логика lteq действует как gt, а gteq действует как lt. Я сам недавно начинаю рубин и рельсы. Так что скажи мне, если я сделал что-то не так. :) Спасибо!

person steve0hh    schedule 26.05.2015

Просто обновление ответа @siddick (которое отлично работает). Теперь вам нужно внести в белый список области, которые предлагает обыск. В случае ответа от @siddick нужно сделать так:

def self.ransackable_scopes(auth_object = nil)
  %i(age_between)
end

Для получения дополнительной информации см. документы - https://github.com/activerecord-hackery/ransack#using-scopesclass-methods

person mikedhart    schedule 26.09.2014