2012-10-06 11 views
17

Mam standardowy kontroler RESTful, który używa silnych parametrów.CanCan load_and_authorize_resource wyzwala Niedozwolone atrybuty

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 

W moim config/initializers Mam plik strong_parameters.rb

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

Kiedy dodać prostego połączenia do kankana za load_and_authorize_resource uzyskać

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)>' 

Gdzie @attr w teście jest zdefiniowany jako

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

W testach mam wszystko poprawnie skonfigurowane, aby zalogować użytkownika i dać im niezbędne role dla administratora, więc wiem, że to nie to. Nie wiem, dlaczego powoduje to wywołanie ForbiddenAttributes. Jestem pewien, że jest to coś prostego, co przeoczyłem. Czy ktoś inny napotkał ten problem i znalazł rozwiązanie tego problemu?

Odpowiedz

19

Uważam, że dzieje się tak dlatego, że CanCan użyje własnej metody gettera dla żądanego zasobu, jeśli nie wczyta go wcześniej z filtrem before_filter. Więc można dodać to do sterownika i powinno działać:

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

    load_and_authorize_resource 

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

(A następnie zrobić to samo dla działań edit/update.)

+0

wierzę, mam ten sam problem. Czy mógłbyś dokładniej wyjaśnić swoje rozwiązanie? –

+6

Minęło trochę czasu, ale dam mu szansę;) Jaka część sprawia ci kłopot? Zasadniczo, jeśli wywołasz "load_and_authorize_resource" canana, spróbuje załadować najbardziej "logiczny" zasób, biorąc pod uwagę nazwę kontrolera, która poprzedza działanie silnego parametru gem. W tym przypadku spróbuje zbudować użytkownika, '@user = User.new (params [: user])' Ale strong_parameters nie pozwoli na masowe przypisanie w ten sposób. Jeśli użyjesz 'before_filter' do ustawienia zmiennej instancji @user, CanCan po prostu użyje tego. Jeśli twój 'before_filter' jest zgodny z argumentem strong_parameters, nie powinien wywoływać błędu. –

+0

Ahhh Bardzo doceniane! Nie rozumiałem, w jaki sposób CanCan "... [wykorzystuje] swoją własną metodę pozyskiwania ...", ale teraz ma to sens. Dzięki jeszcze raz! –

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

Główny akcent tutaj na ** przed_filtr ** nadchodzi przed ** load_and_authorize_resource ** – Ger