Один контроллер, разные представления для обычных пользователей и администраторов - PullRequest
6 голосов
/ 24 августа 2009

в моем приложении у меня есть модель "Пользователь". Каждый пользователь может иметь несколько (email) адресов, которые определены в модели «Адрес»:

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 в зависимости от режима работы. Я могу думать только о двух способах достижения этого:

  1. Сделайте режим работы (нормальный / привилегированный) известным в классе AddressController (используя переменную экземпляра, например, @privileged) и используйте оператор «if» в представлении.
  2. Используйте что-то вроде "after_filter" в контроллере адресов для рендеринга другого макета.

Если возможно отобразить результаты выполнения одного контроллера в двух совершенно разных макетах, в зависимости от режима его работы, каков хороший способ достижения этого?

Заранее спасибо Stefan

Ответы [ 5 ]

9 голосов
/ 24 августа 2009

Вы можете указать, какой вид использовать для отображения результата действия в самом действии. Вы также можете указать, какой макет тоже использовать. Так, например:

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 является необязательным и относится к макету в представлениях / макетах. Существуют различные другие параметры вызова рендеринга, которые вы можете найти в документации для рендеринга .

6 голосов
/ 24 августа 2009

Вы можете указать макет представления для этого конкретного контроллера или всего приложения в контроллере приложения с помощью:

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 Поиск макетов

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

3 голосов
/ 24 августа 2009

Вы можете просто вызвать метод render вручную в конце действия вашего контроллера:

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, чтобы передать явный файл шаблона методу рендеринга.

2 голосов
/ 24 августа 2009

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

Ответ, который вы приняли (это нормально и работает!), Имеет другой макет и другое представление. Мне кажется, что контроллер делает слишком много - я бы разделил это на контроллер администратора.

0 голосов
/ 24 августа 2009

Вы должны поместить административные действия в административное пространство имен и ограничить его там. Создайте каталог с именем 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.

...