Модель Rails, View, Controller и Helper: что и где?

155

В Ruby on Rails Development (или MVC в целом), какое быстрое правило я должен следовать относительно того, куда поместить логику.

Пожалуйста, ответьте утвердительно: « Сделай это, поставь здесь» , а не « Не ставь» .

theschmitzer
источник

Ответы:

173

MVC

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

Представление : представление должно содержать только минимальный код для отображения ваших данных (модель), оно не должно выполнять большую обработку или вычисление, оно должно отображать данные, рассчитанные (или обобщенные) моделью или сгенерированные из контроллера. Если вашему представлению действительно требуется выполнить обработку, которую не может выполнить модель или контроллер, поместите код в помощник. Много Ruby-кода в представлении делает разметку страниц трудной для чтения.

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

pauliephonic
источник
2
Люди начинают отходить от жирной модели. Мне нравится думать о моей модели как о структуре данных. Затем я пишу некоторый объект Ruby, который реализует поведение, инициализируя его моделью (он обрабатывает модель как ее данные так же, как вы можете рассматривать строки и массивы как данные в объектах вне Rails). Вот хорошее видео с примером этой техники.
Джошуа Чик
@AdamDonahue Я не уверен, что что-нибудь может быть воспринято как хорошая вещь. Тонны обязанностей лучше принадлежать к услугам.
фатухоку
35

Добавить к ответу Полифоника:

Помощник : функции, облегчающие создание представления. Например, если вы всегда просматриваете список виджетов, чтобы отобразить их цену, поместите его в помощник (вместе с частичным для фактического отображения). Или, если у вас есть кусок RJS, который вы не хотите загромождать видом, поместите его в помощник.

jcoby
источник
На самом деле мы не помещаем метод sign_in в Helper? Как было предложено RoR Учебник здесь >>> ruby.railstutorial.org/book/...
Иван Ван
14

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

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

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

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

Søren Spelling Lund
источник
Это отличный ответ :)
Карлос Мартинес
12

Прекрасные объяснения здесь уже, одно очень простое предложение в качестве заключения и легко запомнить:

Нам нужны SMART-модели, THIN-контроллеры и DUMB Views.

http://c2.com/cgi/wiki?ModelViewController

maddin2code
источник
7

Поместите вещи, связанные с авторизацией / контролем доступа в контроллер.

Модели все о ваших данных. Валидация, Отношения, CRUD, Бизнес-логика

Представления о показе ваших данных. Отображение и получение только ввода.

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

Мне нравится думать о контроллере как о охраннике / регистраторе, который направляет вас клиента (запрос) к соответствующему счетчику, где вы задаете кассиру (просмотр) вопрос. Затем рассказчик (представление) идет и получает ответ от менеджера (модели), которого вы никогда не видите. Затем вы возвращаетесь к охраннику / администратору (контролеру) и ждете, пока вас направят к другому кассиру (представление), который скажет вам ответ, который менеджер (модель) сказал им в ответ на вопрос другого кассира (представление). ,

Аналогично, если вы хотите сказать кассиру (просмотреть) что-то, то в основном происходит то же самое, за исключением того, что второй кассир скажет вам, принял ли менеджер вашу информацию. Также возможно, что охранник / администратор (контролер), возможно, сказал вам, чтобы вы пошли в поход, так как вы не были уполномочены сообщить менеджеру эту информацию.

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

srboisvert
источник
4

Одна вещь, которая помогает правильно разделить - это избегать анти-паттерна «передавать локальные переменные из контроллера для просмотра». Вместо этого:

# app/controllers/foos_controller.rb:
class FoosController < ApplicationController

  def show
    @foo = Foo.find(...)
  end

end

#app/views/foos/show.html.erb:
...
<%= @foo.bar %>
...

Попробуйте переместить его в метод получения, который доступен как вспомогательный метод:

# app/controllers/foos_controller.rb:
class FoosController < ApplicationController

  helper_method :foo

  def show
  end

  protected

  def foo
    @foo ||= Foo.find(...)
  end

end

#app/views/foos/show.html.erb:
...
<%= foo.bar %>
...

Это облегчает изменение того, что помещается в "@foo" и как оно используется. Это увеличивает разделение между контроллером и представлением, не делая их более сложными.

Джеймс А. Розен
источник
ммм ... Юк. Можете ли вы добавить несколько веских причин / сценариев, когда вы это сделаете. Это разбивает KISS и YAGNI и очень вонючий (просто чтобы
добавить
2
1) Rails делает много магии, чтобы скопировать переменные экземпляра контроллера в ваш экземпляр представления. 2) Предлагаемая реализация также загружает foo, только если к ней обращаются, что может сэкономить некоторую работу в некоторых случаях. Важный ответ действительно 1), хотя.
веб-
11
Вздох Это ужасно. Совместное использование переменных экземпляра Rails - это не анти-шаблон. Это вездесущий синтаксический сахар с низким уровнем умственных способностей, который редко, если вообще вызывает проблемы реального мира. Если вам это не нравится, хорошо, но кодирование вокруг него с нестандартной структурой в стиле барокко делает вещи бесконечно хуже. В этом случае вы фактически делаете foo глобальной (в любом случае на контроллер) переменной. Попытка исправить воспринимаемое злоупотребление изменяемой областью видимости путем значительного увеличения области действия является крайне ироничной.
gtd
1
Я не покупаю это, dasil003. Область действия fooи из @fooних одинакова - они оба ограничены парой <ControllerClass, request>. Кроме того, используя версию получателя, я могу изменить способ Fooобнаружения / хранения / кэширования этого объекта без изменения способа доступа к нему.
Джеймс А. Розен
1
Я думаю, что вы имеете в виду «шаблон переменных». Экземпляр var будет пропускать состояние для всего рендера, даже в глубоко вложенных партиалах. У вашего решения также есть утечка состояния, но оно немного лучше, чем у экземпляра var, потому что оно не допускает переназначения. Передача local на самом деле лучше, потому что это похоже на вызов метода; местные не видны по частям. Смотрите этот ответ .
Кельвин
2

Ну, это отчасти зависит от того, с чем связана логика ...

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

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

Модель: требования проверки, отношения данных, методы создания, методы обновления, методы уничтожения, методы поиска (обратите внимание, что у вас должны быть не только общие версии этих методов, но и если вы что-то делаете, например, находите людей с красным волосы по фамилии, тогда вы должны извлечь эту логику, чтобы все, что вам нужно сделать, это вызвать find_redH_by_name ("кузнец") или что-то в этом роде)

Представление: это должно быть все о форматировании данных, а не обработке данных.

Контроллер: здесь идет обработка данных. Из Интернета: «Цель контроллера - ответить на запрошенное пользователем действие, принять любые параметры, которые пользователь установил, обработать данные, взаимодействовать с моделью, а затем передать запрошенные данные в окончательном виде на Посмотреть."

Надеюсь, это поможет.

Пол Уикс
источник
0

Проще говоря, как правило, модели будут иметь все коды, связанные с таблицами, их простыми или сложными отношениями (представьте их как SQL-запросы, включающие несколько таблиц), манипулирование данными / переменными для получения результата с использованием бизнес-логики. ,

Контроллеры будут иметь код / ​​указатели на соответствующие модели для запрашиваемой работы.

Представления будут принимать пользовательский ввод / взаимодействие и отображать полученный ответ.

Любое существенное отклонение от этого создаст нежелательную нагрузку на эту часть, и это может повлиять на общую производительность приложения.

Anutosh
источник
-1

Тестирование, тестирование ... Поместите в модель как можно больше логики, и тогда вы сможете правильно ее протестировать. Модульные тесты проверяют данные и способ их формирования путем тестирования модели, а функциональные тесты проверяют способ ее маршрутизации или управления с помощью тестирования контроллеров, поэтому из этого следует, что вы не можете проверить целостность данных, если они не находятся в модель.

J


источник