2013-05-15 3 views
1

Как получить тот же результат, но как метод posts - простая ассоциация?
Я хочу сделать это: «user.posts.active». Лучшее решение для определения: finder_sql?Несколько ассоциаций как один

class User < ActiveRecord::Base 
    has_many :created_posts, class_name: Post.name, foreign_key: :creator_id 
    has_many :updated_posts, class_name: Post.name, foreign_key: :updater_id 

    def posts 
     (created_posts + updated_posts).flatten.uniq 
    end 
end 
+0

Необычно видеть «Post.name» вместо «Post». Использование строки имеет то преимущество, что не принудительно загружает модель «Post». То, что вы делаете, может непреднамеренно вводить круговые зависимости, если 'Post' имеет ссылку на' User.name'. – tadman

+0

Ну, прибыль в том, что я использую IDE, и я могу реорганизовать имя класса без больших проблем, я не могу опечатать, из-за синтаксиса. Я пытаюсь использовать Class.name везде, где могу. Я не понял, почему зависимость так плоха, можете ли вы предоставить мне больше информации? Спасибо. – fantgeass

+0

Если, например, 'User' имеет отношение к' Post', а 'Post' имеет отношение к' User', вы будете иметь циклическую зависимость. Класс 'User' не может полностью загрузиться до тех пор, пока' Post' не будет полностью загружен, так как вы бы указали на 'Post.name', а' Post' не может полностью загрузиться, пока не будет загружен «Пользователь», поскольку вы указали «Пользователь» .name'. Помните, что опечатки не являются проблемой, если у вас есть соответствующие модульные тесты, которые их поймают. – tadman

ответ

3

Вместо того, чтобы загружать оба набора сообщений и затем uniqing их в Ruby, вы можете сделать это немного более эффективным, имеющим SQL только дать вам уникальный список.

class User < ActiveRecord::Base 
    def posts 
    Post.where(["creator_id = ? OR updater_id = ?", self.id, self.id]) 
    end 

    ... 
end 

Причина этого является более эффективным, потому что он выдает один запрос БДА с помощью одного набора строк ответа, дубликаты никогда не возвращаются, чтобы начать с, и ActiveRecord только тогда конкретизирует объекты рубина для этого набора строк ,

Для сравнения, подход в исходном вопросе задает два запроса БД, каждый из которых создает массив из User объектов, а затем объединяет эти два массива, а затем удаляет дубликаты. Инициализация дополнительных объектов, затем объединение массивов, а затем итерации по объединенному массиву, необходимые для удаления дубликатов, все вместе взятые, - это основная часть накладных расходов.

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

На стороне записки ...

С отношениями, как это определено, если два пользователя обновить ту же должность, один за другим, не только самый последний пользователь имеет свой идентификатор, назначенный updater_id? Это то, что вы намерены?

В зависимости от дизайна вашего приложения может быть лучше записать обновления самостоятельно, так что все пользователи, которые отредактировали данное сообщение, будут иметь этот пост в своем списке updated_posts.

+0

Это лучше, чем загрузка двух разных запросов и их разбиение. – tadman

+0

Я знаю, что моя реализация сосет, это просто для демонстрации результатов. Я хочу что-то вроде: 'has_many: posts, merge: [: created_posts,: updated_posts]' Но кажется, что это невозможно сейчас. О стороне примечание: это просто пример. – fantgeass

+0

Cool. Удачи с вашим проектом. – jefflunt