Один контроллер, разные представления для обычных пользователей и администраторов
-
19-09-2019 - |
Вопрос
в моем приложении у меня есть "пользовательская" модель.Каждый пользователь может иметь несколько адресов (электронной почты), которые определены в модели "Адрес".:
Class User < ActiveRecord::Base
has_many :addresses
def is_authorized(op)
# returns true or false
end
def is_owned_by(user)
# returns true or false
end
end
Class Address < ActiveRecord::Base
belongs_to :user
end
Внутри класса AddressController текущий вошедший в систему пользователь доступен в переменной экземпляра "@user".Контроллер запрещает обычным пользователям редактировать, удалять, просматривать и т.д.адреса, которые им не принадлежат, но он разрешает пользователю с правами администратора редактировать их.Класс AddressController может запросить AddressModel, выполняет ли пользователь, вошедший в систему в данный момент, обычные операции или операции суперпользователя.
Все это прекрасно работает, и обновления базы данных производятся, как и ожидалось, однако мне бы очень хотелось иметь разные представления HTML в зависимости от режима работы.Я могу придумать только два способа достичь этого:
- Сделайте режим работы (обычный / привилегированный) известным в классе AddressController (используя переменную экземпляра, например@privileged) и используйте оператор "if" в представлении.
- Используйте что-то вроде "after_filter" в контроллере адресов для отображения другого макета.
Если возможно отобразить результаты выполнения одного контроллера в двух совершенно разных макетах, в зависимости от его режима работы, каков хороший способ добиться этого?
Заранее спасибо Стефан
Решение
Вы можете указать, какое представление использовать для отображения результата действия в самом действии.Вы также можете указать, какой макет использовать.Так, например:
def my_action
if @user.is_authorised(...)
render :action => 'admin_action', :layout => 'admin'
else
render :action => 'non_admin_action', :layout => 'non_admin'
end
end
Это приведет к тому, что либо admin_action.html.erb
или non_admin_action.html.erb
в зависимости от возвращаемого значения из is_authorised
.В :layout
опция, э-э, необязательна и ссылается на макет в views / layouts .Существуют различные другие варианты вызова рендеринга, которые вы можете найти в документация для рендеринга.
Другие советы
Вы можете указать макет представления для этого конкретного контроллера или всего приложения в application controller с помощью:
class SomeController < ApplicationController
layout :set_layout
def set_layout
@user.is_authorized(...) ? "privileged_layout" : "normal_layout"
end
...
end
Вы можете попытаться разобраться в этом здесь: http://guides.rubyonrails.org/layouts_and_rendering.html#using-render, под 2.2.12 Поиск Макетов
Надеюсь, это поможет =)
Вы можете просто вызвать визуализировать используйте метод вручную в конце действия вашего контроллера:
if @privileged
render :action => 'show_privileged'
else
render :action => 'show'
end
Это окажет app/views/myview/show_privileged.html.erb
или app/views/myview/show.html.erb
.В качестве альтернативы, вы можете использовать :template
возможность предоставить явный файл шаблона методу рендеринга.
Если это единственный контроллер в вашем приложении, где вы используете if / else повсюду, это, вероятно, нормально.Если вы начнете использовать этот тип логики везде, это должно сказать вам, что вы делаете слишком много сразу.
Ответ, который вы приняли (который прекрасен и работает!) имеет другой макет и другое представление, для меня это говорит о том, что контроллер делает слишком много - я бы разделил это на контроллер администратора.
Вы должны поместить административные действия в административное пространство имен и ограничить их там.Создайте каталог под названием admin
в вашем каталоге контроллеров и добавьте туда _application_controller.rb_:
class Admin::ApplicationController < ApplicationController
before_filter :check_authorized
private
def check_authorized?
if !logged_in? || !current_user.admin?
flash[:notice] = "You've been very bad. Go away.
redirect_to root_path
end
end
end
Теперь вы можете поместить контроллеры в это пространство имен и заставить их наследовать от Admin::ApplicationController
слишком.