2014-10-03 4 views
0

Я использую CanCanCan и Rails 4, поэтому каждое действие разрешено методом load_and_authorize_resource. Все работает, кроме создания действия, с ошибкой: ActiveModel :: ForbiddenAttributesErrorCanCanCan и ForbiddenAttributesError

Я думаю, проблема в CanCan, потому что «create» отлично работает без «load_and_authorize_resource».

class BuildingsController < ApiController 
    load_and_authorize_resource 
    PERMITTED_PARAMS = [:name, :description, deal_info_attributes: [:for_rent, :for_sale, :available_from]] 

    def create 
    building = Building.new(create_params.permit(PERMITTED_PARAMS)) 
    building.author_id = current_user.id if user_signed_in? 

    if building.save 
     render json: building 
    else 
     render json: { errors: building.errors }, status: :bad_request 
    end 
    end 
end 

class ApiController < ActionController::API 
    def create_params 
    params.require(controller_name.classify.downcase.to_sym) 
    end 
end 

Тест:

describe "POST /buildings" do 
    let(:attrs) { attributes_for(:building) } 
    let(:deal_info_attributes) { attributes_for(:deal_info) } 

    it "creates right building" do 
    api_post "/buildings", building: attrs.merge({ name: "SomeBC", deal_info_attributes: deal_info_attributes }) 
    expect(response).to be_success 
    end 
end 

Модель:

class Building < ActiveRecord::Base 
    accepts_nested_attributes_for :deal_info 
    has_one :deal_info, as: :deal_infoable, dependent: :destroy 
    # deal_info is polymorphic 
end 

Способность:

class Ability 
    include CanCan::Ability 

    def initialize(user, ip=nil) 
    user ||= User.new # guest user (not logged in) 

    if user.roles.blank? 
     can :read, :all 
    elsif has_local_role?(user) && has_local_ip?(user, ip) 
     create_permissions(user) 
    elsif has_local_role?(user) && !has_local_ip?(user, ip) 
     raise CanCan::AccessDenied 
    else 
     create_permissions(user) 
    end 
    end 

private 

    def create_permissions(user) 
    # Permissions example: { 'can' => [{ 'read' => 'all' }, { 'update' => 'room' }], 'cannot' => { 'create' => 'building' } } 
    user.roles.each do |role| 
     role.permissions.each do |rights, value| 
     # Check for the value length is a 'fix' for parsing nested json, e.g. [{},{}] 
     value.length > 1 ? value.each{ |v| parse_permissions(rights, v, user) } : parse_permissions(rights, value, user) 
     end 
    end 
    end 

    def parse_permissions(rights, value, user) 
    value.each do |action, subject| 
     case rights 
     when "can" 
     subject == 'all' ? (can action.to_sym, :all) : (can action.to_sym, subject.classify.constantize) 
     when "cannot" 
     subject == 'all' ? (cannot action.to_sym, :all) : (cannot action.to_sym, subject.classify.constantize) 
     when "only_own" 
     can action.to_sym, subject.classify.constantize, subject.classify.constantize.where(author_id: user.id) do |subj| 
      subj.author_id == user.id 
     end 
     end 
    end 
    end 

    # has_local_role and has_local_ip not relevant to the problem. 
end 

+0

Есть что-то странное в отношении того, как эти модели структурированы. Вы должны создать deal_info, который принадлежит _ зданию, но вы делаете наоборот. Или вы можете сделать другой путь и сделать здание property_to: deal_info – coorasse

+0

В здании есть одна сделка (предложение), я думаю, что все в порядке :) В любом случае все работало до сих пор. – Evgeny

+0

Можете ли вы опубликовать свою модель способностей? – Joel

ответ

0

Проблема была в .permit, я должен был добавить ее непосредственно к методу create_params.

class ApiController < ActionController::API 
    def create_params 
    params.require(controller_name.classify.downcase.to_sym).permit(self.class::PERMITTED_PARAMS) 
    end 
end 
Смежные вопросы