Почему бы не обратиться к хешу сеанса на уровне модели? - PullRequest
2 голосов
/ 01 марта 2012

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

Свертывая аутентификацию с нуля, я обнаружил, что мучаюсь и всплываю повсюду из-за отсутствия способности формулировать простые тесты (сеанс также недоступен для инфраструктуры тестирования).Моя схема аутентификации, как почти все, что я видел в rails, хотела использовать сессионный хэш в качестве постоянного слоя, чтобы сохранить идентификатор для модели User «текущего пользователя».Разве это не кажется НАМНОГО больше похожим на модель, чем на артефакт контроллера?

Запахи кода очевидны всякий раз, когда вы смотрите на «типичный» контроллер сессий (этот от превосходных скринкастов Райана Бейтса).Отчаянно пытаясь перенести эту концепцию в состояние покоя, мы видим нездоровый язык, такой как:

def create 
  user = User.find_by_email(params[:session][:email])
  if user && user.authenticate(params[:session][:password])
    session[:user_id] = user.id
    redirect_to root_url, notice: "Logged in!"
  else
    flash.now.alert = "Email or password is invalid"
    render "new"
  end
end

Для меня это запах кода, явно перегруженный контроллер, который кричит о рефакторинге!Но мы не можем.Зачем?Ах, да, потому что MVC - это нарушение ссылки на сеанс, который используется в качестве настойчивого юриста в модели.WTF?Разве это не говорит вам что-то, что мы, похоже, хотим ВЫЗЫВАТЬ ЭТОТ REST RESOURCE / сеансы?

Чтобы понять, почему это просто странно, посмотрите на свои виды входа в систему - html с ручной кодировкой или используйтеAPI "_tags"?Если бы у нас была модель ActiveModel, чтобы сделать этот код, то код создания мог бы выглядеть как обычный скаффолдинг или, возможно, даже уменьшаться до однострочного "response_with".

def create 
  recognition = Recognition.new(params[:user])
  if recognition.save
    redirect_to root_url, :notice => "Thank you for signing up!"
  else
    render "new"
  end
end

Затем взгляните наhtml с ручной кодировкой для всех этих просмотров!Если Распознавание было моделью, сохраняемой сессией (или каким-либо другим способом, который не должен быть обязанностью уровня контроллера в любом случае), то вы могли бы просто использовать построитель форм или simple_form для генерации форм.Конечно, мы могли бы просто передать хеш сессии методу распознавания класса "new_login", скажем, Recognition.on(session).new(params[:recognition]), но это кажется уродливее, чем должно быть.Возможно, это присуще, поскольку мы захотим использовать ссылку на current_user позже на прикладном уровне, возможно, Recognition.on(session).current_user аналогично тому, как можно использовать одноэлементный шаблон?

Просто попробуйте собрать свой пакет аутентификации со строгимBDD, и честно скажи мне, что ты не пронзил эту часть?Если бы у нас была модель Recognition, вся эта вещь была бы сведена к простому набору модульных тестов без хакерских атак.Теперь вместо этого у нас есть «единственный» вариант использования для интеграционного тестирования, магических вторжений модулей ActiveController и взломов для ускорения любого приемочного тестирования предиката logged_in_as.

Я думаю, что весь смысл ActiveModel заключался в том, чтобы облегчить это.вид переосмысления и рефакторинга.Не все модели используют «базу данных».Почему бы не продолжать "сеанс"?

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

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

1 Ответ

1 голос
/ 01 марта 2012

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

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

def create
  Creator.create(params) # Pass all params to the creator model, which will automatically detect what object you're trying to create, make it, and then render the appropriate view
end

def show
  Shower.show(params) # Find the model object and the view based on the params and render them together
end

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

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

Все это говорит о том, что модель сеанса, которую вы предлагаете, на самом деле довольно хорошая идея ... и, следовательно, она уже существует.;) Платформа authlogic имеет модель Sessions: при входе в систему с использованием authlogic вы создаете новую UserSession с объектом params.UserSessions находятся в папке моделей и существуют исключительно для абстрагирования от мелочей аутентификации в класс модели с поддержкой контроллера, так что если это то, что вы ищете, это уже сделано для вас!Проверьте документацию и примеры использования в репозитории authlogic github .

Хотя я бы по-прежнему не хотел передавать любой тип состояния контроллера в настоящую модель ActiveRecord.Позвольте вашим контроллерам манипулировать моделями и отображать результаты этих манипуляций в виде HTML - для этого они и нужны!

...