Метод Ruby ‘.find’ возвращает только первое вхождение

#ruby-on-rails #ruby

#ruby-на-рельсах #ruby #ruby-on-rails

Вопрос:

У меня есть следующие модели: пользователь имеет множество целей, Цель имеет множество задач, задача имеет множество day_tasks. Я пытаюсь написать метод, который находит все day_tasks, которые

  1. принадлежит определенному пользователю
  2. есть :target_date == Date.today (target_date — это столбец в таблице day_tasks).

Я хочу поместить результаты в массив @day_tasks.

мой код:

 @user = current_user
@day_tasks = DayTask.find { |x| x.task.goal.user == @user amp;amp; x.target_date == Date.today }
  

Этот код возвращает только первую запись, соответствующую этим критериям. Я также пробовал использовать DayTasks.где метод с тем же кодом в фигурных скобках, но у меня просто ошибка «Неправильное количество аргументов (0 для 1)». Может ли кто-нибудь объяснить, почему мой метод возвращает только первое вхождение и в чем именно разница.найти и .где?

Комментарии:

1. Я не использую rails, но предполагается, что обычный ruby find возвращает первый найденный элемент, в то время find_all как возвращает все из них, возможно, стоит попробовать, если find_all работает в вашем случае.

2. @derp Я попытался использовать find_all, но получил ошибку неопределенного метода. Запустил DayTask.response_to? :find_all и, конечно же, вернул false …

3. @derp: find_all устарел в Rails 3, заменен на find(:all) . Лучшим решением является использование where , как показано в моем ответе.

4. Спасибо, Райан, я еще не изучал Rails, но подумал, что, возможно, стоит попробовать.

Ответ №1:

Вы написали это:

 @day_tasks = DayTask.find { |x| x.task.goal.user == @user amp;amp; x.target_date == Date.today }
  

find Метод здесь фактически возвращается к Enumerable ‘s find , который является псевдонимом for detect , который принимает блок и возвращает первый элемент в этой коллекции, который соответствует условиям блока или будет возвращен nil .

Чтобы исправить это, вам нужно будет использовать материал запросов ARel, встроенный в ActiveRecord.

 DayTask.joins(:task => { :goals => :user }).where("users.id = ? AND day_tasks.target_date = ?", @user.id, Date.today)
  

Приведенный joins здесь метод будет объединять таблицы, которые соответствуют именам ассоциаций в вашей DayTask модели и связанных моделях. Это означает, что у вас должна быть task ассоциация с DayTask моделью, и для этой модели есть goals ассоциация, а для модели целей есть одна user .

Затем where будет создано условие SQL, которое будет запрашивать объединения, чтобы найти все записи, принадлежащие пользователю и имеющие target_date значение на сегодняшний день.

Комментарии:

1. Очень информативно, спасибо за это объяснение! Хотя прямо сейчас я просто пытаюсь заставить этот метод работать, я рассмотрю правильный способ сделать это позже.

2. @Grant: этот способ — это способ заставить его работать и правильный способ.

3. В качестве небольшого улучшения предложение where должно работать просто как where(:target_date => Date.today, :goals => {:user => current_user}) . Я думаю, нет необходимости переходить на SQL.

Ответ №2:

пожалуйста, проверьте интерфейс запроса ActiveRecord для Rails 3.x :

http://m.onkey.org/active-record-query-interface

http://guides.rubyonrails.org/active_record_querying.html

вероятно, вам понадобится find(:all, …) или where()

Комментарии:

1. Спасибо за ссылки, они очень пригодятся в будущем!

2. извините.. это была опечатка с моей стороны … 😛

3. Пожалуйста, добавьте соответствующую информацию в свой ответ.