Rails: Skinny Controller против Fat Model, или я должен сделать свой контроллер анорексиком - PullRequest
10 голосов
/ 31 марта 2010

Я знаю, что на подобные вопросы уже давали ответы, например:

  • Куда должна идти логика
  • где выполнять определенные задачи и т. Д.

Но у меня есть более конкретный вопрос - как далеко я должен взять эту аксиому: сделай свой контроллер худым, сделай свою модель толстой!

Вот пример:

Например, допустим, у меня есть несколько источников данных для проверки. Хорошим примером будет номер VIN - Я могу проверить это по источникам данных производителей, источникам данных DMV, а также по моим локальным базам данных - чтобы посмотреть, что у меня есть в записи. Итак, у меня есть модель под названием Vin и vins_controller. Внутри модели у меня 5 методов:

  • check_against_local_db
  • check_against_dmv
  • check_against_car_maker_1
  • check_against_car_maker_2 и т. Д.

В моем контроллере, поддерживающем REST, в действии show - у меня есть простая инструкция case, которая смотрит на параметры [: source] и основанная на указанном источнике - вызовет специальный метод проверки.

Теперь вот вопрос: Должен ли я оставить логику, которая определяет, какой источник данных вызывать в контроллере, или я должен переместить его в модель, а затем в контроллере просто сделать что-то вроде check_vin (source, vin)?

Должен ли я сделать мой контроллер анорексиком?

EDIT

Я переключаю это на официальный ответ от @ jay-godse (спасибо - в то время это был хороший ответ). С 2010 года многое изменилось, и этот вопрос по-прежнему получает некоторые взгляды - так что, надеюсь, это укажет некоторым людям правильное направление и поможет им правильно организовать свой код.

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

Ответы [ 5 ]

19 голосов
/ 31 марта 2010

Есть старая поговорка,

Умные структуры данных и тупой код работает намного лучше чем другой путь вокруг.

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

Контроллер анорексии является признаком хорошо спроектированных (умных?) Данных. Мой опыт подсказывает мне, что чем больше усилий вы вкладываете в разработку ваших данных, тем меньше кода вам приходится писать в целом.

Контроллеры лучше всего разбирают входные данные, вызывают соответствующие модели и затем форматируют выходные данные.

4 голосов
/ 31 марта 2010

Я бы добавил логику в мою модель, особенно если я использую TDD (а я всегда использую TDD, за исключением случаев, когда я этого не делаю). Тестирование модели обычно намного проще, чем тестирование контроллера.

3 голосов
/ 31 марта 2010

Мне нравится подходить к таким вопросам, думая об ответственности. Что в этом случае «отвечает» за проверку VIN? Модель. Контроллер просто для передачи параметров ... для "управления" на основе ввода пользователя.

Если это не совсем понятно, подумайте об этом так: где размещение этого кода вызовет наименьшее влияние, если его нужно будет использовать повторно? Скажите ... если два разных действия на двух разных контроллерах требуют проверки VIN, что нужно сделать? Если вы оставили этот код в контроллере, вам, по сути, пришлось бы дублировать его и в новом контроллере, но если бы вы поместили его в модель, вы просто вызвали бы метод check_vin из нового контроллера, и никакого кода дублирование будет необходимо. Распределяя обязанности там, где они наиболее целесообразны, вы повысили возможность повторного использования своего кода.

2 голосов
/ 23 ноября 2015

Вы должны попробовать Первопроходец . Это тонкий фреймворк поверх Rails (на самом деле, он работает со всеми фреймворками Ruby), он вводит уровень сервиса, объекты форм, перенаправление между персистентностью и кодом домена и т. Д.

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

Например, зачем вам вдавливать логику проверки в контроллер и модель, если у вас есть объект формы для этого?

2 голосов
/ 31 марта 2010

Контроллер обязан "разобрать" params, но проверка должна быть выполнена в модели.

Я бы сделал что-то подобное на контроллере:

@my_model = MyModel.new(:source => params[:source] ...)
if(@my_model.valid?)
  # treat valid model here (i.e. save the model and redirect to show)
else
  # treat validation error here (usually throw an error)
end

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

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