4

認証にはDeviseを使用し、役割管理にはRolifyを使用し、承認にはCanCan2.0を使用しています。

:adminロールがユーザーのロールを変更できるようにしようとしていますが、他のすべてのユーザーのアクセスを禁止しています。

これが私が試したが機能していないものです:

#ability.rb
class Ability
  include CanCan::Ability

  def initialize(user)
    if user.has_role? :admin
      can :access, :all
    elsif user.has_role? :moderator
      can [:index, :read, :update, :destroy], :users, :user_id => user.id
      cannot :access, :users, [:role_ids]
    end
end

#application_controller.rb
...
rescue_from CanCan::Unauthorized do |exception|
    redirect_to root_url, :alert => exception.message
  end

ユーザーフォームに意図的に関連付けを残しました。

#_form.html.erb
<%= simple_form_for @user do |f| %>
  <%= f.association :roles, as: :check_boxes %>
  <%#= f.association :roles, as: :check_boxes if can? :update, @user, :roles %>
  <%= f.button :submit %>
<% end %>

コントローラ

#users_controller.rb
class UsersController < ApplicationController

  before_filter :authenticate_user!
  load_and_authorize_resource

  def index
    @users = User.accessible_by(current_ability)
  end

  def new
    @user = User.new
  end

  def create
    @user = User.new(params[:user])
  end

  def show
    @user = User.find(params[:id])
  end

  def edit
    @user = User.find(params[:id])
  end

  def update
    @user = User.find(params[:id])

    @user.update_without_password(params[:user])

    if successfully_updated
      redirect_to @user
    else
      render :action => "edit"
    end
  end
end

およびモデル:

#user.rb
    class User < ActiveRecord::Base
      rolify

      attr_accessible :role_ids
    ...

ここで、:moderatorの役割を持つユーザーが、別のユーザー(または自分の)の役割を変更しようとすると、次のようになります。

  1. CanCan :: Unauthorized例外がスローされ、ユーザーはroot_urlにリダイレクトされます
  2. ユーザーの役割が変更されます

私は混乱しています。例外が発生した場合、なぜ変更がまだ行われているのですか?私はおそらく非常に間違ったことをしています:)

users_controller.rbのユーザーの役割に応じてクエリパラメータを操作しようとしました。defupdateの直後にログステートメントを配置すると、次のように出力されます。

2013-04-24 12:42:21 [4161] DEBUG    (0.1ms)  BEGIN
2013-04-24 12:42:21 [4161] DEBUG    (0.3ms)  INSERT INTO "users_roles" ("user_id", "role_id") VALUES (5, 1)
2013-04-24 12:42:21 [4161] DEBUG    (0.4ms)  COMMIT
2013-04-24 12:42:21 [4161] DEBUG   User Load (0.5ms)  SELECT "users".* FROM "users" WHERE "users"."id" = $1 LIMIT 1  [["id", "5"]]
2013-04-24 12:42:21 [4161] DEBUG {"username"=>"Blabla", "email"=>"bla@bla.com", "password"=>"", "password_confirmation"=>"", "approved"=>"1", "role_ids"=>["1", "2", ""]}

私は何かを見落としているに違いない...

4

4 に答える 4

1

まず、現時点では少し混乱しているように見えるので、おそらく自分の能力をクリーンアップしたいと思うでしょう。他のすべてを無視すると、わかりやすくするために、パスワードを変更するためのカスタムアクションを指定することをお勧めします。例えば:

# ability.rb

def initialize(user)
  ...

  cannot :manage_roles, :user
  if user.has_role? :admin
    can :manage_roles, :user
  else
end

(残りのルールで正確に何を達成しようとしていますか?現在、モデレーターに自分自身のみの読み取り、編集、削除を許可していると思われる場合、これは意図したことですか?)

フォームで実際に何もできない人のために、フォームの役割セクションを非表示にするか無効にすることをお勧めします。

#_form.html.erb
<%= simple_form_for @user do |f| %>
  <%= f.association :roles, as: :check_boxes if can? :manage_roles, @user %>
  <%= f.button :submit %>
<% end %>

can?(アクションとオブジェクト/クラスの2つの引数のみを取ることに注意してください。)

さらに安全にしたい場合は、コントローラーで次のチェックを使用することもできます。

# users_controller.rb
def update
  @user = User.find(params[:id])

  user_params = params[:user]
  if cannot? :manage_roles, @user
    user_params.delete_if { |k, v| k.to_sym == :role_ids }
  end

  if @user.update_without_password(user_params)
    redirect_to @user
  else
    render :action => "edit"
  end
end

(paramsハッシュから削除する正しいキーが何であるかを再確認する必要があります。これ:role_idsはあなたのに基づいていると思いますattr_accessibleが、simple_formについてはよくわかりません。)

于 2013-04-24T01:25:23.533 に答える
0

users/_form.html.erbファイル内でこれを使用してロールをラップします。

シンプルな形で:

<% if can? :manage, User %>
  <%= f.association :roles, as: :check_boxes %>
<% end %>

単純な形式なし:

<% if can? :manage, User %>
    <div class="control-group">
      <%= f.label :roles, class: "control-label" %>
      <div class="controls">
        <% Role.all.each do |role| %>
            <%= check_box_tag "user[role_ids][]", role.id, @user.role_ids.include?(role.id) %>
            <%= role.name %><br />
        <% end %>
      </div>
    </div>
<% end %>
于 2013-04-22T22:38:15.137 に答える
0

モデレーターに何をしてもらいたいかわかりませんが、ここに私が使用する基本的な構成があります。私は可能な限りあなたのシナリオにそれを適応させました。モデレーターが個人の権利を必要としない場合は、単純に内側の句を削除してください。

class Ability
  include CanCan::Ability

  def initialize(user)
    # Create guest user aka. anonymous (not logged-in) when user is nil.
    user ||= User.new

    if user.has_role? :admin
      can :manage, :all
    elsif user.has_role? :moderator
      can :manage, User, user_id: user.id
      can :create, User
      can :read, :all
    else
       # Guest user aka. anonymous
      can :read, :all
    end
  end
end
于 2013-04-24T00:01:56.557 に答える
0

私は次のようにbefore_filterを使用することになりました:

before_filter :prevent_unauthorized_role_setting, :only => [ :create, :update ]

def prevent_unauthorized_role_setting
  if cannot? :manage_roles, current_user
    params[:user].delete_if { |k, v| k.to_sym == :role_ids }
  end
end

ability.rbでZaidの提案に従いながら:

cannot :manage_roles, :users
if user.has_role? :admin
  can :manage_roles, :users
end

また、Rolifyを削除し、自分で役割を管理しました。

于 2013-04-26T09:35:43.577 に答える