Ассоциация Rails has_many и has_many через одну и ту же модель STI

У меня есть модель Note. Заметки очень полезны и используются во многих целях в приложении.

У нас есть еще одна модель User, и это STI, разделенные между User1 и User2.

У нас есть третья модель Thing, то есть вещи, принадлежащие Пользователям... Я пока оставлю ее там, так как она становится немного сложнее (есть и другие модели, немного похожие на вещи, о которых также можно делать заметки) .

Note.rb
belongs_to :user #This signifies that the user wrote the note
belongs_to :notable, polymorphic: :true #This is what the note is referring to

User.rb
has_many :user_notes, class_name: "Note", foreign_key: "user_id" 
#signifies the note was written by the User

User1.rb < User
has_many :notes, as: :notable 
#Signifies the note was about the User1
has_many :things

User2.rb < User
has_many :notes, as: :notable 
#Signifies the note was about the User2


Thing.rb
belongs_to :user1
has_many :notes, as: :notable 
#The note is about the thing

Они могут быть, но обычно не самореферентными (я пишу заметку о себе).

Часто User1 пишут заметки о User2 или о вещах User2, чтобы User2 мог их увидеть.

Я думаю, что выбрал правильный путь, переименовав файл user_notes.

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

Есть ли простой способ сделать это? Я борюсь с двумя моментами.

  1. Как я могу связать заметки о своих вещах?

    has_many :thing_notes, через: :things, источник: :notes

работает, но мне интересно, правильный ли это подход.

Кроме того, меня интересует обратное (что тоже полезно), в данном случае игнорирование того, кто мог написать заметку, чтобы вернуть соответствующий user1, если он есть. Но...

delegate :user1, to: :notable

не имеет смысла, если user1 уже является потенциальным notable_type.

  1. Как я могу сопоставить все свои заметки (любого типа) и вернуть их?

i.e.

@user1.notes 

вернет только заметки обо мне

@user1.user_notes 

вернет заметки, которые я написал

@user1.thing_notes 

вернет заметки о моих вещах

Я мог бы объединить их вместе, но я рискую получить раздражающие дубликаты, и кажется позорным делать несколько вызовов базы данных и терять порядок БД, когда они все одного типа...

Есть ли очевидный способ получить все мои заметки...?

Note.where("(user_id = :user1_id) OR (notable_id = :user1_id AND notable_type = 'User') OR (notable_type = 'Thing' AND notable_id IN (:things))", user1_id: user1.id, things:user1.thing_ids)

это прикосновение к уродливой стороне и станет только уродливее ...

Надеюсь, это имеет смысл для тех, кто любит решать такие головоломки...


person Carpela    schedule 26.01.2017    source источник
comment
Есть ли причина не иметь Thing с belongs_to :user вместо user1?   -  person Ho Man    schedule 26.01.2017
comment
С точки зрения системной логики, да. У User2 нет вещей. (Хотя у них есть вещи 2 и вещи 3, ради аргумента).   -  person Carpela    schedule 26.01.2017


Ответы (1)


Для сопоставления, если вы используете Rails 5, вы можете сделать что-то вроде этого, чтобы упростить необработанный SQL:

Note.where(user: user1).or(Note.where(notable: user1)).or(Note.where(notable: user1.things))

Если вы не используете Rails 5, вы можете включить эту жемчужину для той же функциональности: https://github.com/Eric-Guo/where-or

person Ho Man    schedule 26.01.2017
comment
Пока не собираюсь переходить на Rails 5. Нужно избегать этой боли, где это возможно. Я проверю этот драгоценный камень. Определенно делает запрос немного чище. тогда вопрос в том, как бы вы предложили использовать этот запрос. Есть ли способ разумно интегрировать это с активной записью или областями? Или просто используйте его как метод экземпляра для User1? Или, возможно, метод/область действия класса для заметок, а затем рекурсивно вызвать его. Я подумывал поставить области таким образом, чтобы у меня могли быть .all_notes или .notes_about_me (чтобы исключить написанные мной заметки, которые не касались меня). - person Carpela; 26.01.2017
comment
Если вы хотите получить к ним доступ по отдельности в какой-то момент, тогда области действия имеют смысл. Их можно использовать как методы экземпляра. - person Ho Man; 27.01.2017