2012-10-06 47 views
17

我有一個使用強參數的標準RESTful控制器。CanCan load_and_authorize_resource觸發器禁止的屬性

class UsersController < ApplicationController 
    respond_to :html, :js 

    def index 
    @users = User.all 
    end 

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

    def new 
    @user = User.new 
    end 

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

    def create 
    @user = User.new(safe_params) 

    if @user.save 
     redirect_to @user, notice: t('users.controller.create.success') 
    else 
     render :new 
    end 
    end 

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

    if @user.update_attributes(safe_params) 
     redirect_to @user, notice: t('users.controller.update.success') 
    else 
     render :edit 
    end 
    end 

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

    if current_user != @user 
     @user.destroy 
    else 
     flash[:error] = t('users.controller.destroy.prevent_self_destroy') 
    end 
    redirect_to users_url 
    end 

    private 

    def safe_params 
    safe_attributes = 
     [ 
     :first_name, 
     :last_name, 
     :email, 
     :password, 
     :password_confirmation, 
     ] 
    if current_user.is?(:admin) 
     safe_attributes += [:role_ids] 
    end 
    params.require(:user).permit(*safe_attributes) 
    end 
end 

在我config/initializers我有一個文件strong_parameters.rb

ActiveRecord::Base.send(:include, ActiveModel::ForbiddenAttributesProtection) 

當我添加一個簡單的調用慘慘的load_and_authorize_resource我得到

1) UsersController POST create with invalid params re-renders the 'new' template 
Failure/Error: post :create, user: @attr 
ActiveModel::ForbiddenAttributes: 
    ActiveModel::ForbiddenAttributes 
# ./spec/controllers/users_controller_spec.rb:128:in `block (4 levels) in <top (required)>' 

@attr在測試中被定義爲

before(:each) do 
    @attr = 
     { 
     first_name: "John", 
     last_name: "Doe", 
     email: "[email protected]", 
     password: "foobar", 
     password_confirmation: "foobar" 
     } 
    end 

在測試中,我已將所有設置正確地登錄到用戶,併爲他們提供了成爲管理員的必要角色,所以我知道不是這樣。我不知道爲什麼這會導致ForbiddenAttributes觸發。我確信這是我忽視的簡單事情。有沒有其他人遇到過這個問題,並找到了解決辦法?

回答

19

我相信這是因爲CanCan會爲請求的資源使用自己的getter方法,如果您不用before_filter預加載它的話。所以,你可以添加此控制器,它應該工作:

class UsersController < ApplicationController 
    before_filter :new_user, :only => [:new, :create] 

    load_and_authorize_resource 

    def new_user 
    @user = User.new(safe_params) 
    end 
end 

(然後做編輯/更新動作相同。)

+0

我相信我有同樣的問題。你介意進一步澄清你的解決方案嗎? –

+6

已經有一段時間了,但我會給它一個鏡頭;)什麼部分給你帶來麻煩?基本上,如果調用cancan的'load_and_authorize_resource',它會嘗試加載最大的「邏輯」資源,因爲控制器的名稱在強參數gem的操作之前。在這種情況下,它將嘗試構建User,'@user = User.new(params [:user])'但strong_parameters不允許以這種方式進行批量分配。如果你使用'before_filter'來設置@user實例變量,CanCan會直接使用它。如果你的'before_filter'符合strong_parameters,它不應該引發錯誤。 –

+0

啊啊非常感謝!我不理解CanCan是如何「...... [使用]它自己的getter方法......」,但現在很有意義。再次感謝! –

7
before_filter do 
    params[:user] = safe_params 
end 
load_and_authorize_resource 
+1

這裏主要強調** before_filter **在** load_and_authorize_resource之前** – Ger