Как добавить условные предложения where в rails

Я новичок в рельсах и пытаюсь выполнить поиск по таблице с рельсами, и я просто использую для этого свои знания sql. Но это просто не похоже на рельсы или рубин даже...

Есть ли лучший способ сделать то, что я делаю ниже? (в основном, аргументы даты передаются в sql только в том случае, если они заполнены)

def search(begin_date=nil, end_date=nil)

    subject = " and created_at "

    if !(begin_date.nil? || end_date.nil?)
      where_part = subject + "BETWEEN :begin_date AND :end_date"
    else if (begin_date.nil? && end_date.nil?) 
      where_part = ""
    else if(begin_date.nil?)
      where_part = subject + " <= :end_date"
    else if (end_date.nil?)
      where_part = subject + " >= :begin_date"
    end
    end
    end
    end

    User.joins(places: {containers: {label: :user}}).where("users.id= :user_id "+where_part, user_id: self.id, begin_date:begin_date, end_date:end_date).group(...).select(...)
end

ИЗМЕНИТЬ

пользователь.rb

has_many :containers
has_many :user_places
has_many :places, through: :user_places
has_many :labels

место.рб

has_many :containers
has_many :user_places
has_many :users, through: :user_places

контейнер.rb

belongs_to :label
belongs_to :place
belongs_to :user

label.rb

belongs_to :user
has_many :containers

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

Любая из этих дат может быть нулевой, поэтому мне нужно будет указать это в моем «запросе».

Мой вопрос: как я могу сделать это по рельсам? Я просмотрел http://guides.rubyonrails.org/active_record_querying.html и, возможно, я мог бы использовать команду exclude здесь где-нибудь... но эта модель отношений кажется немного сложной для того, чтобы сделать это с ActiveRecord... как я могу?, я действительно думаю, что мне следует использовать ActiveRecord, но как?

Спасибо


person MrWater    schedule 27.07.2012    source источник
comment
[вот хороший пример того, как делать соединения с активной записью][1] [1]: stackoverflow.com/questions/764538/   -  person Frank Visaggio    schedule 27.07.2012
comment
Привет, моя проблема не в соединениях... Я просто не писал их, потому что они не имеют значения. Мое дело с параметрами условного поиска   -  person MrWater    schedule 27.07.2012
comment
@itsalltime - я думаю, что Боб пытается сказать - почему бы не использовать Active Record вместо того, чтобы писать прямой SQL? guides.rubyonrails.org/active_record_querying.html   -  person JasCav    schedule 27.07.2012


Ответы (2)


Вы можете применить несколько вызовов where к запросу, чтобы создать базовый запрос:

query = User.joins(...)
            .group(...)
            .select(...)
            .where('users.id = :user_id', :user_id => self.id)

а затем добавьте еще один вызов where в зависимости от вашего интервала дат:

if(begin_date && end_date)
  query = query.where(:created_at => begin_date .. end_date)
  # or where('created_at between :begin_date and :end_date', :begin_date => begin_date, :end_date => end_date)
elsif(begin_date)
  query = query.where('created_at >= :begin_date', :begin_date => begin_date)
elsif(end_date)
  query = query.where('created_at <= :end_date', :end_date => end_date)
end

Каждый вызов where добавляет еще одну часть к вашему общему предложению WHERE, используя AND, что-то вроде:

q = M.where(a).where(b).where(c)

это то же самое, что сказать WHERE a AND b AND c.

person mu is too short    schedule 27.07.2012
comment
Привет, этот ответ отличный. Спасибо. Кажется, я не могу использовать begin_date .. end_date (и мне пришлось использовать пустое значение вместо nil), потому что я собираю дату и время из текстового поля и преобразовываю их локально. if !begin_date.blank? begin_date = DateTime.strptime("#{begin_date} 00:00:00", "%m/%d/%Y %H:%M:%S").to_datetime end В итоге я воспользовался вашим альтернативным предложением: or where('created_at between :begin_date and :end_date', :begin_date => begin_date, :end_date => end_date) - person MrWater; 28.07.2012
comment
@itsalltime: использование begin_date .. end_date должно работать, если begin_date и end_date являются реальными объектами даты, но похоже, что вместо этого у вас есть строки. Я бы рекомендовал преобразовать их в объекты даты перед их использованием, чтобы вам приходилось беспокоиться о проблемах с форматом даты только в одном месте. - person mu is too short; 28.07.2012
comment
Привет, я конвертирую их с помощью функции, опубликованной выше, но даже в этом случае begin_date .. end_date не работает, и поэтому мне пришлось пойти на альтернативу - person MrWater; 30.07.2012
comment
Я предполагаю, что это, должно быть, была какая-то другая ошибка, так как теперь все в порядке. Теперь моя проблема в том, что created_at применяется к таблице пользователей, и я хотел, чтобы он применялся к контейнерам... Как я могу это сделать? - person MrWater; 30.07.2012

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

Ссылка, объясняющая, как объединять таблицы с активной записью

person Frank Visaggio    schedule 27.07.2012
comment
На самом деле у меня были некоторые сомнения относительно того, как использовать объединения, но я думаю, что нашел способ решить то, что хотел, как я разместил в своем отредактированном ответе. Моя вещь на самом деле с параметрами условного поиска. - person MrWater; 27.07.2012
comment
о, для таких случаев и прочего: rigelgroupllc.com/blog/2014/09/14/ - person Danny; 27.02.2015