一个控制器,对于普通用户和管理员有不同的视图

7

在我的应用程序中,我有一个“用户”模型。每个用户可以拥有多个(电子邮件)地址,这些地址在“地址”模型中定义:

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类中使操作模式(normal/privileged)可知(使用实例变量,例如@privileged),并在视图中使用“if”语句。
2.在地址控制器中使用类似“after_filter”的东西来呈现不同的布局。
如果可以根据其操作模式在两个完全不同的布局中显示单个控制器的执行结果,那么实现这一点的好方法是什么?
谢谢Stefan提前
5个回答

10

你可以在操作本身中指定要使用哪个视图来显示结果。你也可以指定要使用哪个布局。例如:

def my_action
  if @user.is_authorised(...)
    render :action => 'admin_action', :layout => 'admin'
  else
    render :action => 'non_admin_action', :layout => 'non_admin'
  end
end

根据is_authorised返回的值,将呈现admin_action.html.erbnon_admin_action.html.erb:layout选项是可选的,并引用视图/布局中的布局。渲染调用中还有各种其他选项,您可以在渲染文档中找到。


谢谢。但是如果我这样做的话,似乎会偏离“约定优于配置”的路径。我有点担心 - 这是我的第一个Rails应用程序 - 我是否应该与其他人似乎都在做的事情不同? - cite
好吧,可以说惯例是为一个操作渲染一个视图,但我明白你的意思。如果你只是想要不同的布局,那么Staelen的解决方案是一个很好的选择。如果你真的想根据操作中的逻辑呈现不同的视图,那么我不确定这是否足够接近基本惯例,以便不指定要呈现哪个视图。 - Shadwell
我想我会尝试使用Staelen的布局解决方案,以及您提供要呈现的模板。再次感谢。 - cite

7
您可以通过以下方式指定特定控制器或整个应用程序的视图布局:

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 找到布局下方。
希望这能帮到你 =)

哦,这是一个好主意。非常感谢! - cite

4

您可以在控制器操作的末尾手动调用渲染方法:

if @privileged
    render :action => 'show_privileged'
else
    render :action => 'show'
end

这将呈现app/views/myview/show_privileged.html.erbapp/views/myview/show.html.erb。另外,您可以使用:template选项向呈现方法提供明确的模板文件。

2

如果您的应用中只有这一个控制器需要使用if/else语句,那么这可能是可以接受的。但如果您在每个地方都这样做的话,那就意味着您一次要处理太多东西了。

您所接受的答案(很好,也可以工作!)具有不同的布局和视图,对我来说这意味着该控制器正在做过多的工作——我会将其拆分成一个管理员控制器。


这个。你是对的。我试图一次做太多的事情 - 在两种操作模式下拥有所有这些动作可靠可用的想法太过诱人。我写了一个专门的管理控制器。谢谢。 - cite

1

您应该将管理操作放在管理命名空间中,并在那里进行限制。在您的控制器目录中创建一个名为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

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接