Rails 4 + Rolify Gem:不会通过UI更新用户角色 [英] Rails 4 + Rolify Gem: User roles aren't being updated via UI

查看:109
本文介绍了Rails 4 + Rolify Gem:不会通过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 Role
  • id (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虚拟属性添加到R​​ole:

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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆