Rails 4 + Rolify Gem:不会通过UI更新用户角色 [英] Rails 4 + Rolify Gem: User roles aren't being updated via UI
问题描述
我有一个编辑视图,该视图允许我为特定用户更新角色.我已经包含了下面的代码,但是,只是为了给您一个思路,当我取消选中页面上的框时,我在控制器中的puts语句会正确地识别出角色关联是错误的,并且可以在日志的更下方看到.
I have an edit view that allows me to update roles for a particular user. I've included the code below, however, just to give you an idea, when I uncheck the boxes on the page, my puts statements in my controller correctly picks up that the role association is false and can be seen further down in the logs.
但是,在稍后的日志中,您可以看到角色被重新关联回"true",而且我不确定为什么是这种情况!
However, later in the logs, you can see that the roles are being re-associated back to 'true' and I'm not sure why that's the case at all!
如果未选中此复选框,我希望将这些角色从用户中删除.
If the checkboxes are unchecked, I want those roles to be removed from the user.
users/edit.html.erb:
<fieldset>
<%= form_for @user, :url => {action: "update"}, :html => { :class => 'user-role' } do |f| %>
<h1 class="h1-heading">User Roles</h1>
<p class="user-paragraph"> Check the boxes to grant different roles to <%= @user.first_name %> <%= @user.last_name %>:</p>
<%= f.label(:admin) do %>
<%= hidden_field_tag(:admin, 0) %>
<%= check_box_tag(:admin, 1, @user.has_role?(:admin)) %>
Administrator
<% end %>
<%= f.label(:member) do %>
<%= hidden_field_tag(:member, 0) %>
<%= check_box_tag(:member, 1, @user.has_role?(:member)) %>
Member
<% end %>
<%= f.submit class: 'btn btn-primary-dialog pull-right' %>
<% end %>
</fieldset>
users_controller.rb:
def update
@user = User.find(params[:id])
@customer = current_user.customer
@logged_in_user = User.find_by_email(current_user.email)
if params[:admin] == "1"
@user.grant(:admin)
elsif params[:admin] == "0"
@user.remove_role(:admin)
end
if params[:member] == "1"
@user.grant(:member)
elsif params[:member] == "0"
@user.remove_role(:member)
end
puts "NEW ROLES"
puts @user.has_role? :member
puts @user.has_role? :admin
if @user.update_attributes(params[:user])
puts "UPDATING USER"
puts @user.has_role? :member
puts @user.has_role? :admin
redirect_to '/users/show', :flash => { :alert => 'User was successfully updated.' }
end
end
end
日志:
如下所示,它返回"false",然后在更新属性时,将角色再次设置为"true",我无法弄清楚发生的原因或原因!
As you can see below, it returns 'false' and then when updating the attributes, sets the roles again to 'true' and I cannot figure out where or why that's happening!
Started PATCH "/users/51" for 127.0.0.1 at 2015-06-26 13:48:58 +1000
Processing by UsersController#update as HTML
Parameters: {"utf8"=>"✓", "authenticity_token"=>"+qNti57HxMa2B/a+c6nS71Qp0p7hf+kTE4b5eiBI4No=", "admin"=>"0", "member"=>"0", "commit"=>"Update User", "id"=>"51"}
User Load (0.5ms) SELECT `users`.* FROM `users` WHERE `users`.`id` = 1 ORDER BY `users`.`id` ASC LIMIT 1
Customer Load (0.3ms) SELECT `customers`.* FROM `customers` WHERE `customers`.`email` = 'ryan@ryandrake.com' LIMIT 1
Company Load (0.2ms) SELECT `companies`.* FROM `companies` WHERE `companies`.`domain` = 'ryandrake.com' LIMIT 1
CustomerAccess Load (0.3ms) SELECT `customer_accesses`.* FROM `customer_accesses` WHERE `customer_accesses`.`customer_id` = 1 LIMIT 1
User Load (0.3ms) SELECT `users`.* FROM `users` WHERE `users`.`id` = 51 LIMIT 1
CACHE (0.0ms) SELECT `customers`.* FROM `customers` WHERE `customers`.`email` = 'ryan@ryandrake.com' LIMIT 1
User Load (0.2ms) SELECT `users`.* FROM `users` WHERE `users`.`email` = 'ryan@ryandrake.com' LIMIT 1
Role Load (0.3ms) SELECT `roles`.* FROM `roles` INNER JOIN `users_roles` ON `roles`.`id` = `users_roles`.`role_id` WHERE `users_roles`.`user_id` = 51 AND `roles`.`name` = 'admin'
(0.1ms) BEGIN
(0.2ms) DELETE FROM `users_roles` WHERE `users_roles`.`user_id` = 51 AND `users_roles`.`role_id` IN (9)
(0.9ms) COMMIT
(0.3ms) SELECT COUNT(count_column) FROM (SELECT 1 AS count_column FROM `users` INNER JOIN `users_roles` ON `users`.`id` = `users_roles`.`user_id` WHERE `users_roles`.`role_id` = 9 LIMIT 1) subquery_for_count
Role Load (0.3ms) SELECT `roles`.* FROM `roles` INNER JOIN `users_roles` ON `roles`.`id` = `users_roles`.`role_id` WHERE `users_roles`.`user_id` = 51 AND `roles`.`name` = 'member'
(0.1ms) BEGIN
(0.2ms) DELETE FROM `users_roles` WHERE `users_roles`.`user_id` = 51 AND `users_roles`.`role_id` IN (3)
(0.4ms) COMMIT
(0.5ms) SELECT COUNT(count_column) FROM (SELECT 1 AS count_column FROM `users` INNER JOIN `users_roles` ON `users`.`id` = `users_roles`.`user_id` WHERE `users_roles`.`role_id` = 3 LIMIT 1) subquery_for_count
NEW ROLES
Role Load (0.7ms) SELECT `roles`.* FROM `roles` INNER JOIN `users_roles` ON `roles`.`id` = `users_roles`.`role_id` WHERE `users_roles`.`user_id` = 51 AND (((roles.name = 'member') AND (roles.resource_type IS NULL) AND (roles.resource_id IS NULL)))
false
Role Load (0.6ms) SELECT `roles`.* FROM `roles` INNER JOIN `users_roles` ON `roles`.`id` = `users_roles`.`role_id` WHERE `users_roles`.`user_id` = 51 AND (((roles.name = 'admin') AND (roles.resource_type IS NULL) AND (roles.resource_id IS NULL)))
false
(0.3ms) BEGIN
Customer Load (0.3ms) SELECT `customers`.* FROM `customers` WHERE `customers`.`email` = 'ryan.drake2@otherlevels.com' LIMIT 1
ExtraCustomerAccount Load (0.6ms) SELECT `extra_customer_accounts`.* FROM `extra_customer_accounts` WHERE `extra_customer_accounts`.`email` = 'ryan.drake2@otherlevels.com' LIMIT 1
Customer Load (0.3ms) SELECT `customers`.* FROM `customers` WHERE `customers`.`id` = 1 LIMIT 1
Company Load (0.2ms) SELECT `companies`.* FROM `companies` WHERE `companies`.`domain` = 'otherlevels.com' LIMIT 1
Company Load (0.2ms) SELECT `companies`.* FROM `companies` WHERE `companies`.`name` = 'None' ORDER BY `companies`.`id` ASC LIMIT 1
Role Load (0.3ms) SELECT `roles`.* FROM `roles` WHERE `roles`.`name` = 'member' AND `roles`.`resource_type` IS NULL AND `roles`.`resource_id` IS NULL ORDER BY `roles`.`id` ASC LIMIT 1
Role Exists (0.2ms) SELECT 1 AS one FROM `roles` INNER JOIN `users_roles` ON `roles`.`id` = `users_roles`.`role_id` WHERE `users_roles`.`user_id` = 51 AND `roles`.`id` = 3 LIMIT 1
(0.2ms) SELECT `roles`.id FROM `roles` INNER JOIN `users_roles` ON `roles`.`id` = `users_roles`.`role_id` WHERE `users_roles`.`user_id` = 51
Role Load (0.2ms) SELECT `roles`.* FROM `roles` WHERE `roles`.`id` = 3 LIMIT 1
Role Load (0.3ms) SELECT `roles`.* FROM `roles` INNER JOIN `users_roles` ON `roles`.`id` = `users_roles`.`role_id` WHERE `users_roles`.`user_id` = 51
(0.2ms) INSERT INTO `users_roles` (`user_id`, `role_id`) VALUES (51, 3)
Role Load (0.6ms) SELECT `roles`.* FROM `roles` WHERE `roles`.`name` = 'admin' AND `roles`.`resource_type` IS NULL AND `roles`.`resource_id` IS NULL ORDER BY `roles`.`id` ASC LIMIT 1
Role Load (0.3ms) SELECT `roles`.* FROM `roles` WHERE `roles`.`id` IN (3, 9)
(0.2ms) INSERT INTO `users_roles` (`user_id`, `role_id`) VALUES (51, 9)
(0.3ms) COMMIT
UPDATING USER
Role Load (0.4ms) SELECT `roles`.* FROM `roles` INNER JOIN `users_roles` ON `roles`.`id` = `users_roles`.`role_id` WHERE `users_roles`.`user_id` = 51 AND (((roles.name = 'member') AND (roles.resource_type IS NULL) AND (roles.resource_id IS NULL)))
true
Role Load (0.3ms) SELECT `roles`.* FROM `roles` INNER JOIN `users_roles` ON `roles`.`id` = `users_roles`.`role_id` WHERE `users_roles`.`user_id` = 51 AND (((roles.name = 'admin') AND (roles.resource_type IS NULL) AND (roles.resource_id IS NULL)))
true
Role Load (0.3ms) SELECT `roles`.* FROM `roles` INNER JOIN `users_roles` ON `roles`.`id` = `users_roles`.`role_id` WHERE `users_roles`.`user_id` = 1 AND (((roles.name = 'otherlevels_admin') AND (roles.resource_type IS NULL) AND (roles.resource_id IS NULL)))
Redirected to http://localhost:3000/users/show
Completed 302 Found in 80ms (ActiveRecord: 15.1ms)
在指出无法正确更新参数的地方方面将提供帮助!
Would love any help with pointing out where it's not correctly updating the params!
推荐答案
您的主要问题在这里:
@user.update_attributes(params[:user_id])
与我最初的解决方案不同,这不需要简单的表格.
Unlike my original solution this does not require simple form.
首先让我们设置表单:
<%= form_for(@user, url: {action: "update"}, html: { class: 'user-role' }) do |f| %>
<h1 class="h1-heading">User Roles</h1>
<p class="user-paragraph"> Check the boxes to grant different roles to <%= @user.first_name %> <%= @user.last_name %>:</p>
<%= f.fields_for(:roles) do |r| %>
<%= r.hidden_field :name unless r.object.persisted? %>
<%= r.label :_keep do %>
<%= r.check_box :_keep, checked: r.object.persisted? %>
<%= r.object.name %>
<% end %>
<% end %>
<% end %>
我们将为角色传递一些嵌套属性:
We are going to pass some nested attributes for roles:
-
name
(适用于新角色) -
_keep
虚拟属性-我们是否保存角色 -
id
(如果存在该角色,则由rails自动插入)
name
(for new roles)_keep
a virtual attribute - do we save the Roleid
(automatically inserted by rails if the role exists)
然后我们将用户类别修改为accepts_nested_attributes_for :roles
Then we modify the user class to accepts_nested_attributes_for :roles
class User < ActiveRecord::Base
rolify
accepts_nested_attributes_for :roles,
allow_destroy: true,
reject_if: ->(hash){ hash["_keep"] != "1" }
end
注意reject_if: ->(hash){ hash["_keep"] != "1" }
,这意味着如果未选中此复选框,则我们不会创建角色,而allow_destroy会在我们通过_delete=true
时删除该角色.
Note reject_if: ->(hash){ hash["_keep"] != "1" }
which means that if the checkbox is unchecked we do not create a Role, and allow_destroy which will delete the role if we pass _delete=true
.
我们需要将_keep
虚拟属性添加到Role:
We need to add the _keep
virtual attribute to Role:
class Role < ActiveRecord::Base
has_and_belongs_to_many :users, :join_table => :users_roles
belongs_to :resource, :polymorphic => true
validates :resource_type,
:inclusion => { :in => Rolify.resource_types },
:allow_nil => true
scopify
attr_accessor :_keep
AVAILABLE_ROLES = %w{ administrator member }
end
我们还添加了一个AVAILABLE_ROLES常量,以便获得角色列表.
We also add a AVAILABLE_ROLES constant so that we can get a list of the roles.
class UsersController < ApplicationController
before_action :set_user, only: [:show, :edit, :update, :destroy]
# ...
# GET /users/1/edit
def edit
# Seed checkboxes for roles
Role::AVAILABLE_ROLES.each do |role|
# This adds an unsaved role to the user if it does not exist
@user.roles.build(name: role) unless @user.has_role?(role)
end
end
# PATCH/PUT /users/1
def update
if @user.update(update_params)
redirect_to @user, notice: 'User was successfully updated.'
else
render :edit
end
end
private
# Use callbacks to share common setup or constraints between actions.
def set_user
@user = User.find(params[:id])
end
# Only allow a trusted parameter "white list" through.
def user_params
params.require(:user).permit(:username, :email, roles_attributes: [:name, :id, :_keep, :_destroy])
end
def update_params
user_params.tap do |o|
# Adds the _delete attribute if the keep checkbox is unchecked
o[:roles_attributes] = o[:roles_attributes].map do |k,h|
attrs = h.merge(_destroy: (h[:_keep] != "1"))
# Don't let the user update the name of an existing Role!
# This would let a malicious user to grant any role.
h.key?(:id) ? attrs.except(:name) : attrs
end
end
end
end
这篇关于Rails 4 + Rolify Gem:不会通过UI更新用户角色的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!