Подклассирование модели User действительно плохо в Rails? - PullRequest
9 голосов
/ 27 мая 2011

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

Мне также нужен способ для полиморфного поведения.Например, многие методы будут вести себя по-разному в зависимости от типа.Разве это не то, для чего нужен полиморфизм?

Но дело в том, что я всегда получаю отпор от Rails.По умолчанию - особенно то, как формы отправляются в хэши параметров - похоже, работают как модели без подклассов.Ссылки и хэши параметров - это всего лишь два способа, которыми значения по умолчанию вас кусают.

Каков "правильный" способ обработки сложной логики для различных типов пользователей в Rails?В Java работает модель подклассов - вам не нужно проходить через обручи, чтобы заставить ее работать так, как вы хотите.Но в Rails трудно заставить подклассы работать с соглашениями REST, он наказывает вас, когда вы забыли включить :as => :user, или он наказывает вас, когда вы помещаете подклассный объект в ссылки, такие как edit_user_path(@user) <- плохая идея!</p>

Есть еще одна область, с которой также очень трудно иметь дело.Допустим, у меня есть модель Company, и у нее много Users.Эти пользователи могут быть директорами, инструкторами, стажерами и т. Д. - все это разные подклассы.

Когда мы создаем учетную запись, мы можем захотеть использовать accepts_nested_attributes_for :users.Однако, если мы используем это, мы не можем указать классы, которые он создает.Черт побери!

Кажется, что все в Rails разработано так, чтобы не хотеть, чтобы вы делили свои модели на подклассы.Если вы не подкласс, все «просто работает».Но если вы подкласс, вы попадете в ад.

Какое решение?

Ответы [ 3 ]

3 голосов
/ 27 мая 2011

Вообще говоря, наследование в Ruby не рекомендуется в пользу смешанного поведения и делегирования.Ruby и Rails могут делать такие вещи, но это имеет тенденцию приводить к откату, о котором вы упомянули

Ваш конкретный пример звучит как случай делегирования: имейте класс User, который принадлежит сотруднику (или наоборот).Специфичное для данного типа поведение этого сотрудника (например, директор, инструктор и т. Д.) Относится к конкретному классу сотрудников.Затем пользователь делегирует, как обрабатывать определенные сценарии сотруднику, к которому он присоединился

1 голос
/ 23 марта 2013

Речь идет, в основном, о «скажи, что ты имеешь в виду»,

платформа не может знать, когда вы говорите redirect_to @user, имеете ли вы в виду универсальную пользовательскую форму или специализированную пользовательскую форму сотрудника.

Это приводит к большому количеству redirect_to @user.becomes(User), которое вы можете СУШИТЬ до

def to_base_class
  becomes User
end
alias_method :to_b, :to_base_class

и напишите redirect_to @user.to_b, когда вы хотите перенаправить на User, а не Employee resource

По сути, элегантный синтаксис, такой как redirect_to @user, представляет очень глубокую связь между моделью и представлением / контроллером, и по мере того, как вы делаете логику модели и представления / контроллера, возникают более сложные трещины из-за этой связи, и потребуются дополнительные усилия по разделению домена или потребуется написать немного больше кода.

Rails не наказывает вас за использование ООП, вы испытываете повышенную сложность отношения контроллера <-> представление <-> модели:

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

1 голос
/ 27 мая 2011

Вот трюк, который я понял. Не думайте, что это предполагаемое поведение:

class UserSubclass < User

  def self.model_name
    User.model_name
  end

end

Практически все модели (производные от ActiveModel) по умолчанию идентифицируют себя на основе конкретного имени класса. Это делается с помощью метода класса #model_name (он возвращает экземпляр ActiveModel::Name с self в качестве параметра. Переопределение его для возврата определенного класса выводит Rails на правильный путь. Таким образом, вы сохраняете эту логику в своей модели и из ваших шаблонов.

...