Ruby on Rails:使用Cancan和Devise如何允许用户通过New和Edit Registration Views选择角色?

时间:2014-08-27 19:16:31

标签: ruby-on-rails devise cancan

我使用简单的Todo Rails应用程序的文档实现了Devise和Cancan。我能够为没有管理员角色的用户隐藏内容编辑功能。

但是,我无法验证具有admin roll的用户是否可以访问“编辑”功能,因为我无法添加/编辑用户角色。

如何允许用户通过“新建”和“编辑注册(设计)”视图选择角色?

以下是我要完成的作业:

为您的用户添加多个角色以创建“管理员”

目标:为每个用户设置多个角色以创建管理员。

步骤: 一个。将名称(字符串)的属性添加到“用户”模型中。 湾创建一个名为“role”的新模型,并创建一个名为“user_role”的附加模型。“user_role”模型将是连接表。使用多对多关联,以便用户具有许多user_roles,并且角色具有许多user_roles。 user_role模型应该同时属于用户和角色 C。将admin(string)的属性添加到“角色”模型中。 d。创建一种方法来检查用户是否是“用户”模型中的管理员。您可以使用名为“def admin?”的方法

这是我的代码:

应用程序/模型/ user.rb

  class User < ActiveRecord::Base
    # Include default devise modules. Others available are:
    # :confirmable, :lockable, :timeoutable and :omniauthable
    devise :database_authenticatable, :registerable,
           :recoverable, :rememberable, :trackable, :validatable

    has_many :todos
    has_many :roles, :through => :user_roles

    before_create :setup_default_role_for_new_users

    ROLES = %w[admin user]

    def role_symbols
      [role.to_sym]
    end

    def roles=(roles)
      self.roles_mask = (roles & ROLES).map { |r| 2**ROLES.index(r) }.inject(0, :+)
    end

    def roles
      ROLES.reject do |r|
        ((roles_mask.to_i || 0) & 2**ROLES.index(r)).zero?
      end
    end

    def role?(role) 
      roles.include?(role.to_s)
    end

    def setup_default_role_for_new_users
      if self.role.blank?
        self.role = "user"
      end
    end
  end

app / models / todo.rb

  class Todo < ActiveRecord::Base
    belongs_to :user
  end

应用程序/分贝/迁移/ 20140827183230_add_role_to_users.rb

class AddRoleToUsers < ActiveRecord::Migration
  def change
    add_column :users, :role, :string
  end

  def self.up
    add_column :users, :role, :string
  end

  def self.down
    remove_column :users, :role
  end
end

视图/设计/注册/ new.html.erb

<h2>Sign up</h2>

<%= form_for(resource, as: resource_name, url: registration_path(resource_name)) do |f| %>
  <%= devise_error_messages! %>

  <div><%= f.label :email %><br />
  <%= f.email_field :email, autofocus: true %></div>

  <div><%= f.label :password %> <% if @validatable %><i>(<%= @minimum_password_length %> characters minimum)</i><% end %><br />
    <%= f.password_field :password, autocomplete: "off" %></div>

  <div><%= f.label :password_confirmation %><br />
    <%= f.password_field :password_confirmation, autocomplete: "off" %></div>

    <% for role in Role.all %>
      <div>
        <%= check_box_tag "user[role_ids][]", role.id, @user.roles.include?(role) %>
        <%=h role.name %>
      </div>
    <% end %>
    <%= hidden_field_tag "user[role_ids][]", "" %>

  <div><%= f.submit "Sign up" %></div>
<% end %>

<%= render "devise/shared/links" %>

视图/设计/注册/ new.html.erb

<h2>Edit <%= resource_name.to_s.humanize %></h2>

<%= form_for(resource, as: resource_name, url: registration_path(resource_name), html: { method: :put }) do |f| %>
  <%= devise_error_messages! %>

  <div><%= f.label :email %><br />
  <%= f.email_field :email, autofocus: true %></div>

  <% if devise_mapping.confirmable? && resource.pending_reconfirmation? %>
    <div>Currently waiting confirmation for: <%= resource.unconfirmed_email %></div>
  <% end %>

  <div><%= f.label :password %> <i>(leave blank if you don't want to change it)</i><br />
    <%= f.password_field :password, autocomplete: "off" %></div>

  <div><%= f.label :password_confirmation %><br />
    <%= f.password_field :password_confirmation, autocomplete: "off" %></div>

  <div><%= f.label :current_password %> <i>(we need your current password to confirm your changes)</i><br />
    <%= f.password_field :current_password, autocomplete: "off" %></div>

    <% for role in Role.all %>
      <div>
        <%= check_box_tag "user[role_ids][]", role.id, @user.roles.include?(role) %>
        <%=h role.name %>
      </div>
    <% end %>
    <%= hidden_field_tag "user[role_ids][]", "" %>

  <div><%= f.submit "Update" %></div>
<% end %>

<h3>Cancel my account</h3>

<p>Unhappy? <%= button_to "Cancel my account", registration_path(resource_name), data: { confirm: "Are you sure?" }, method: :delete %></p>

<%= link_to "Back", :back %>

如果需要更多代码示例来帮助回答此问题,请与我们联系。

2 个答案:

答案 0 :(得分:1)

用户无法自行选择角色,您可以从控制台创建角色,然后以管理员身份登录此用户并更改其他用户的角色

答案 1 :(得分:0)

一旦我使用表单的相应代码而不是单独的角色模型,我就能够实现基于角色的授权。

更改为表格:

+  <% for role in User::ROLES %>
+    <%= check_box_tag "user[roles][#{role}]", role, @user.roles.include?(role), {:name => "user[roles][]"}%>
+    <%= label_tag "user_roles_#{role}", role.humanize %><br />
+  <% end %>
+  <%= hidden_field_tag "user[roles][]", "" %>

一旦表单正确显示,它就不会保存对后端的更改。然后我不得不在应用程序控制器中更新参数sanitizer:

+    devise_parameter_sanitizer.for(:sign_up) {|u| u.permit(:email, :password, :password_confirmation, :current_password, roles: [])}
+    devise_parameter_sanitizer.for(:account_update) {|u| u.permit(:email, :password, :password_confirmation, :current_password, roles: [])}

我想关键是要休息一下,不要混淆文档实现。

您可以在todo.startco.de

查看成品