Rails Ассоциации: HABTM? - PullRequest
1 голос
/ 26 ноября 2010

Эй, ребята, я зашел в тупик, подумав об этом слишком долго.

Контекст: учитывая следующие модели:

  • Пользователь
  • Пункт
  • Замок

Вот сценарий: блокировка в основном похожа на «удержание». Пользователь может установить «блокировку» на любой данный элемент, чтобы сообщить системе, что элемент не должен быть удален. Элементы не будут удалены, пока не будет снята блокировка.

Вот сложная часть. Блокировка является собственной моделью, потому что я хочу, чтобы несколько пользователей могли блокировать любой данный элемент. Допустим, Боб блокирует элемент, он еще не существует, поэтому он создает блокировку для этого элемента и информацию о том, что Боб в настоящее время связан с этой блокировкой. Джон приходит и блокирует тот же элемент, но блокировка уже существует, поэтому Джон просто «добавляется» под той же блокировкой. Блокировка не будет снята до тех пор, пока все пользователи не решат «разблокировать» или отсоединить себя от этой блокировки.

Мое замешательство в том, как я должен моделировать эти отношения. Конечно, пользователь может иметь много блокировок, каждая из которых связана с отдельным элементом (поскольку любой данный элемент может иметь не более одной блокировки). Сами замки могут иметь много пользователей. С точки зрения элемента каждый элемент может иметь одну блокировку, связанную со многими пользователями.

Другими словами, я хотел бы получить доступ к информации примерно так:

item.lock.users # get the users 'locking' the item
user.locks # get the items the user is currently 'locking

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

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

Прямо сейчас у меня есть:

  • пользователь имеет и принадлежит ко многим замкам
  • блокировка имеет и принадлежит многим пользователям
  • У пользователя есть много предметов
  • Товар принадлежит пользователю
  • предмет имеет один замок
  • замок принадлежит элементу

Это кажется правильным?

Ответы [ 3 ]

3 голосов
/ 26 ноября 2010

Я думаю, что то, что вы делаете, сработает, хотя вам, возможно, не придется использовать habtm. Что делать, если элемент может иметь много блокировок и может быть удален только тогда, когда у него нет блокировок? Таким образом, вы можете добавить дату / причину / комментарий для каждой блокировки пользователем.

  • пользователь
    • has_many: замки
    • has_many: предметов
  • замок
    • принадлежит_ пользователю:
    • принадлежит_в: элемент
  • пункт
    • принадлежит_: пользователь
    • has_many: замки

Это все еще позволит вам сделать user.locks, хотя item.lock.users не будет работать, но, взглянув на каждую блокировку, вы легко сможете получить пользователей.

item.locks.each do |lock|
    puts lock.user
end
2 голосов
/ 26 ноября 2010

Вам не нужна модель замка. Вы можете просто установить отношения habtm между пользователями и предметами:

class User < ActiveRecord::Base
  has_many :items
  has_and_belongs_to_many :locks, :class_name => "Item"
end

User.first.items # => [<#Item>, <#Item>, ...] # Items created by user
User.first.locks # => [<#Item>, <#Item>, ...] # Items locked by user

class Item < ActiveRecord::Base
  belongs_to :user
  has_and_belongs_to_many :lock_users, :class_name => "User"
end

Item.first.user # => <#User> # Creator of the item
Item.first.lock_users # => [<#User>, <#User>, ...] # "Lockers" of the item

Вам, конечно, нужно будет создать таблицу соединений и помнить, что Rails ожидает, чтобы таблица соединений была названа. Возможно, вам лучше указать опцию :join_table для habtm.

Ключевым моментом здесь является то, что отношения в Rails очень гибкие. Вы можете иметь несколько отношений между двумя таблицами; Вы можете иметь отношения «созданный» и «блокировка» независимо друг от друга. Все, что вам нужно сделать, это использовать разные имена для отношений.

1 голос
/ 26 ноября 2010

Я могу относиться к «размышлениям об этом слишком долго». Когда эта мысль приходит мне в голову, я отступаю и работаю над другими частями кода. Взаимоотношения, кажется, проявляются с течением времени, поскольку они действительно удобны, чтобы избавить нас от написания кода. Они не являются необходимыми, поэтому, по крайней мере, на этапе разработки, мы можем отложить объявление отношений и посмотреть, что нам нужно, чуть позже.

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

Нюхать ... нюхать ... господи, теперь мои боссы знают, что я не идеален ... нюхать ....

Возвращаясь к рассматриваемому вопросу: обычно для блокировок, предотвращающих случайное (или умышленное) удаление, я создаю логическое поле в моей основной таблице и, если эта запись должна быть очищена, задайте для нее значение true. Для того, что вы делаете, я бы, вероятно, полностью избавился от поля флага и имел бы отдельную таблицу, в которой указаны идентификаторы блокируемых записей, а также идентификаторы пользователей, которые хотят сохранить запись. Удалите записи этих пользователей, если / когда они думают, что пришло время удалить запись. Когда пришло время провести некоторую чистку, я бы проверил эту таблицу. Нечто похожее на:

delete from table1 where id not in (select distinct(table1_id) from table2)

Что мне не нравится в этом, так это то, что есть возможность иметь еще одну таблицу, заполненную записями «вести эту запись», и именно тогда я добавляю еще одну таблицу, чтобы пользователи, которые не могут решить, какие вещи должны быть удалены .

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...