如何在控制器中使用两个版本的def更新?
我有一个表单,应该允许管理员编辑比常规用户更多的变量。两者都使用相同的编辑视图。目前,我在控制器中有一个表单和def update
,但无法区分管理员和非管理员。
所以现在我已经向控制器添加了两个不同的strong_params版本。但是如何根据用户的类型应用这些不同的版本?
其中一种方法是使用if else语句重写def update,如果是admin,则需要一个stong_params版本,如果是非admin,则需要另一个strong_params版本。但是,这里的问题是,我无法在此def更新上调用before_action,以测试它是否为管理员。出于安全原因,这可能是必要的。
所以我认为我需要在控制器中使用两种不同的def更新方法:1为管理员调用一个版本的strong_params并为其添加before_action。另一个非管理员使用另一个版本的strong_params(以及不同的before_action)。
我知道如何在控制器中构建它,但不知道如何在编辑视图中告诉表单使用哪个def更新(或者应该在def编辑中指定在控制器?)。 (事实上,我甚至不知道Rails如何知道它应该调用def更新(可能通过资源:路由中的用户?)。)我应该以某种方式编辑编辑视图中的<%= f.submit "Save changes"
行吗? / p>
答案 0 :(得分:2)
我建议在这种情况下使用表格。表单是表示模型的特殊抽象层。这是php-frameworks的术语(如Zend等)。在我的项目中,我通常称它为“类型”。例如:
型号:
class Post < ActiveRecord::Base
validates :body, presence: true
validates :title, presence: true
end
类型:
module BaseType
extend ActiveSupport::Concern
module ClassMethods
def model_name
superclass.model_name
end
def name
superclass.name
end
end
end
class PostEditAdminType < Post # model Post is parent class for type
include BaseType
attr_accessor :current_user
attr_accessible :title, :body # can edit both field title and body
end
class PostEditRegularType < Post
include BaseType
attr_accessor :current_user
attr_accessible :body # can edit body field only
end
控制器
def update
post = Post.find(params[:id])
@post = if current_user.admin?
post.becomes PostEditAdminType
else
post.becomes PostEditRegularType
end
if @post.update_attributes(params[:post])
redirect_to past_path(@past)
else
f(:error)
render :edit
end
end
在我看来,这是非常好的做法和相同案例中的最佳架构。
答案 1 :(得分:1)
form_for只能发送到一个控制器动作。因此,您将需要form_for发送的第三个操作,并且此操作首先确定您是否为admin / non-admin,然后相应地将您发送到两个“def update methods”中的任何一个(使用参数)。例如,(这完全是伪代码)
def receive_form
# create variable 'type' that returns whether you are an admin or non-admin
if type = "Admin"
# send to your 'def update' for admins, whatever you've named this
redirect_to admin_update_path
else
# send to your 'def update' for non-admins
redirect_to non_admin_update_path
end
end
答案 2 :(得分:1)
你可以使用强参数gem,它只允许一些属性。所以你可以写一些与
相关的代码if current_user.admin?
params.require(:user).allow :name, :role
else
params.require(:user).allow :name
end
因此,如果您是管理员用户,则可以更改用户的角色,否则,您只能编辑该名称。
如果您希望普通用户只能编辑他/她的帐户,请结帐cancancan gem。它更有意义,对吗?如果您是普通用户,则只应更新您的帐户。
使用cancancan的示例代码:
class Ability
include CanCan::Ability
def initialize(user)
user ||= User.new
if user.admin?
can :manage, :all
else
can :manage, User, id: user.id
end
end
end
如果您使用带有强参数的rails 4,请不要忘记sanitize your params。
如果您想了解更多详情,请与我们联系。
答案 3 :(得分:0)
我的解决方案将有两个单独的模型,一个用于User
,另一个用于Role
用户。您可能在某些时候拥有的课程多于常规用户和管理员,因此这种方法可以简化长期添加更多角色的过程。
如何做到这一点:
Roles
name
模型
User
模型将具有has_and_belongs_to_many :roles
关系Role
模型将具有has_and_belongs_to_many :users
关系rails g migration CreateRolesUsersTable
has_and_belongs_to_many
语句创建自动使用连接表查找其值的变量。你可以看看这些。您可以通过以下方式检查是否已正确设置:
admin_role = Role.find_by(name: “admin”)
user.roles.include?(admin_role)
您还可以将自己的方法添加到User
模型中供自己使用。这是我的一个样本:
def admin?
self.is_role_by_name?("admin")
end
def add_role(role)
roles << role
end
def add_role_by_name(role_name)
role = Role.find_by(name: role_name)
add_role(role)
end
def remove_role(role)
roles.delete(role)
end
def remove_role_by_name(role_name)
role = Role.find_by(name: role_name)
remove_role(role)
end
def is_role?(role)
roles.to_a.include?(role)
end
def is_role_by_name?(role_name)
role = Role.find_by(name: role_name)
is_role?(role)
end
现在,在您的视图中,您可以使用以下内容显示表单的某些字段:
<% if @user.admin? %>
input whatever here...
<% end %>