Толстые контроллеры в рельсах

Я начал работать с учебным пособием на railstutorial.org, чтобы познакомиться с фреймворком. Мои контроллеры еще не чудовищны, но я вижу, что Single Responsibility Principal (SRP) не является t применяется на протяжении всего руководства, так как выходит за его рамки.

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

Это обычное решение? Или есть лучшие решения?

В мире .net для достижения более чистое разделение интересов (SoC). Однако недавно несколько человек написали новую структуру фронт-контроллера под названием Fubu Behaviours<. /а>. Он прекрасно отражает идею конвейера запросов. Что-то, что имеет все больше и больше смысла для меня.

Чтобы обработать запрос, мы обычно выполняем несколько шагов до (а иногда и после) выполнения действия. В некоторых случаях условное завершение запроса. Кажется естественным использовать что-то вроде поведения, конвейера или шаблона матрешки. Так что каждое звено в цепи отвечает либо за продолжение, либо за прекращение. Наследование не кажется лучшим решением.

Есть ли что-то подобное в рельсах? Будет ли это иметь смысл в рельсах?

Рекомендуемые чтения будут также приветствоваться!


person nieve    schedule 02.10.2012    source источник
comment
Авторизация должна произойти до того, как вы окажетесь запертым в контроллере. И то же самое частично верно для аутентификации: вам нужно будет проверить учетные данные для использования внутри уровня модели, но восстановление личности пользователя из токена также должно происходить за пределами триады MVC. К сожалению, единственный пример, который я могу привести, находится в php, и я не уверен, применим ли он к конкретному рамки. Отношение RoR к MVC довольно расплывчато.   -  person tereško    schedule 03.10.2012


Ответы (3)


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

Это позволяет вам переместить все правила авторизации из ваших контроллеров в манифест (т. е. модель возможностей), требуя от ваших контроллеров только инициировать проверку авторизации через authorize_resource вызов в вашем контроллере. Затем вы можете обрабатывать простые перенаправления в своем ApplicationController:

class ApplicationController < ActionController::Base
  rescue_from CanCan::AccessDenied do |exception|
    if current_user
      redirect_to signin_url, :alert => exception.message
    else
      redirect_to root_path, :alert => exception.message
    end
  end
end

Кроме этого, я бы переместил все вызовы @user = User.find(params[:id]) в фильтр before_filter и очистил ваши отступы и порядок действий (должен быть index, new, create, show, edit, update, destroy), и я думаю, что ваш контроллер был бы хорош и тощий.

person dnatoli    schedule 03.10.2012
comment
Это, наверное, самое близкое, что я получу. Я предполагаю, что есть жемчужины для каждой ситуации, с которой я могу столкнуться. Тем не менее, это означает, что все делается по наследству: у меня, вероятно, есть AuthorizationController, AuthenticationController и так далее... - person nieve; 03.10.2012
comment
НЕЕЕЕТ! создание дополнительных контроллеров для обработки авторизации и т. д. является серьезной плохой практикой. Контроллеры в REST должны быть связаны с ресурсами, а не с функциональностью! ApplicationController предназначен исключительно для настройки, поэтому используйте его для настройки перенаправления авторизации. Дополнительную информацию о ROA см. на странице en.wikipedia.org/wiki/Ресурсно-ориентированная_архитектура. - person dnatoli; 04.10.2012
comment
Подождите, так что тогда вы потенциально можете столкнуться со всевозможной странной логикой в ​​вашем ApplicationController - если, например, есть какие-то конкретные правила, например, о том, куда перенаправлять разные типы пользователей, например, при исключениях авторизации. не говоря уже о том, что в конечном итоге в ApplicationController могут быть втиснуты всевозможные проблемы. - person nieve; 04.10.2012

Честно говоря, я не могу точно сказать, должна ли авторизация/аутентификация быть работой модели или контроллера, и люди дадут вам разные ответы на этот счет. Это как серая зона.

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

person Agis    schedule 02.10.2012
comment
перемещение методов не изменит того факта, что контроллер проверяет авторизацию пользователя. - person tereško; 03.10.2012
comment
Эй, Агис, спасибо за ответ. Что произойдет с более сложными контроллерами, где контроллер позаботится о большем количестве проблем и обязанностей (проверка, авторизация, аутентификация, капча или что-либо еще, что может потребоваться запросу для разрешения рендеринга определенного представления). Так что то, что сказал Терешко, было ударом по деньгам (и с меньшим количеством слов). Я действительно надеялся увидеть, что есть другие способы сделать это в рельсах, более близкие к способу fubu. Но опять же, может быть, это просто я ищу что-то, чего там даже не должно быть..? - person nieve; 03.10.2012
comment
Честно говоря, я еще не дошел до того этапа, когда что-то в моих контроллерах меня бы беспокоило. Я уверен, что есть решения, такие как сфокусированные контроллеры, о которых вы говорили, или абстрагирование таких функций от драгоценных камней (например, разработка драгоценного камня для аутентификации). Но, к сожалению, я не могу предоставить вам определенные подходы к тому, как это сделать. :) - person Agis; 03.10.2012
comment
люди не согласятся, но я считаю, что аутентификация должна происходить ОБА на уровне контроллера и на уровне модели. В некоторых обстоятельствах будет дублирование, но также будет душевное спокойствие. Вы сталкиваетесь с ситуациями, когда в контроллерах слишком много условной логики, и пользователю необходимо иметь доступ к ресурсу. - person timpone; 03.10.2012

Для любой логики авторизации я бы фактически удалил ее из уровня контроллера и переместил на уровень «политики».

используя этот гем: https://github.com/NullVoxPopuli/skinny_controllers он дает вам два дополнительных слоя

  • operations
    • where business logic goes
  • policies
    • where authorization goes

Пример из Readme:

module EventOperations
  class Read < SkinnyControllers::Operation::Base
    def run
      # the business logic here is to only check if we will allow this model
      # to be returned
      model if allowed?
    end
  end
end



class EventPolicy < SkinnyControllers::Policy::Base
  # allowed? from the operation delegates to this method
  # here, you could do whatever logic you need to check if the operation
  # is allowed
  def read?(o = object)
    o.is_accessible_to?(user)
  end
end
person NullVoxPopuli    schedule 25.02.2016