2013-06-10 5 views
2

Я создаю веб-приложение Rails 3.2, и мне нужна помощь в построении SQL-запроса. В моем приложении у меня есть пользователи, проекты и задачи. Пользователи назначаются задачам через таблицу соединений, называемую присваиваниями.Как получить родительские записи на основе дочерних записей

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

Проект

has_many :tasks 

Задача

has_many :assignments 
has_many :users, :through => :assignments 

Пользователь

has_many :assignments 
has_many :tasks, :through => :assignments 

Назначение

belongs_to :user 
belongs_to :task 

Как contruct этот запрос в наиболее эффективной и наилучшей практики пути?

Update

Это, как я, наконец, решил это:

def index 
tasks = current_user.tasks.joins(:project) 
@output = tasks.map{|task| task.project}.uniq 
end 
+0

Очень умная реализация «присоединений» ... это действительно сокращает многословие. Мне нужно помнить об этом в будущем. – zeantsoi

ответ

2

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

# app/models/user.rb 
has_many :tasks, :through => :assignments, :uniq => true 

Затем повторите задачи и скомпилируйте arr ау всех родительских проектов:

tasks = User.first.tasks 
projects = [] 

tasks.each do |task| 
    projects << task.project 
end 

Наконец, удалите все повторяющиеся проекты из массива:

project.uniq! #=> array of `Project` objects 
+0

Отлично! Я должен был сделать это, хотя: проекты << task.project –

+0

Как я могу изменить запрос, поэтому мне не нужно делать выбор SQL (чтобы получить проект) для каждой задачи? –

+0

Честно говоря, я не уверен, что вы можете. Есть несколько ограничений в использовании ActiveRecord (среди прочего, я уверен) как ORM. Поскольку 'tasks' - это объект« ActiveRecord :: Relation », который - в практическом плане - массив, все, что вы можете сделать, - это итерация и запрос каждого члена. AFAIK, ActiveRecord не предоставляет никаких методов автоматического запроса каждого члена массива и сбора того, что возвращается в отдельный 'ActiveRecord :: Relation'.Таким образом, вы можете вручную вручную перебирать «задачи» самостоятельно. – zeantsoi

0

В зависимости от того, насколько велик ваш список задач (это было бы неэффективно для больших списков), вы могли бы сделать это:

Project.where("id in (" + tasks.collect(&:project_id).join(",") + ")").uniq 

Это возвращает проекты (без дубликатов) для задач в задач.

Редактировать - Для 500 детей это заняло 0,001977577 секунд таким образом, и 0.799814631 секунд выше (через tasks.map).

Смежные вопросы