CanCanCan和ForbiddenAttributesError(CanCanCan and ForbiddenAttributesError)
我使用CanCanCan和Rails 4,因此每个操作都由load_and_authorize_resource方法授权。 一切都有效,除了创建动作,它失败并出现错误:ActiveModel :: 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
I use CanCanCan and Rails 4, so every action is authorized by load_and_authorize_resource method. Everything works except create action, it fails with error: ActiveModel::ForbiddenAttributesError
I think the problem is in CanCan, because 'create' works fine without '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
Test:
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
Model:
class Building < ActiveRecord::Base accepts_nested_attributes_for :deal_info has_one :deal_info, as: :deal_infoable, dependent: :destroy # deal_info is polymorphic end
Ability:
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
原文:https://stackoverflow.com/questions/26179102
最满意答案
把你的轴放在一个列表中:
my_axes = [] for n in range(1, 4): my_axes.append(fig.add_subplot(1, 3, n)) for ax in my_axes: ax.set_ylabel('AVG')
Put your axes in a list:
my_axes = [] for n in range(1, 4): my_axes.append(fig.add_subplot(1, 3, n)) for ax in my_axes: ax.set_ylabel('AVG')
相关问答
更多-
动态变量名可以通过特殊的哈希变量.var (和.data_model )与[]运算符结合使用: <#assign x=3> <#list 1..x as i> ${.vars['abc'+ i?c]} #list> Dynamic variable names can be used through special hash variable .var (and .data_model) combined with the [] operator: <#assign x=3> <#list 1 ...
-
把你的轴放在一个列表中: my_axes = [] for n in range(1, 4): my_axes.append(fig.add_subplot(1, 3, n)) for ax in my_axes: ax.set_ylabel('AVG') Put your axes in a list: my_axes = [] for n in range(1, 4): my_axes.append(fig.add_subplot(1, 3, n)) for ax in my ...
-
按变量名称循环(Loop by variable names)[2022-02-22]
如果你真的想使用循环,你可以尝试: ind<-combn(3,2) for(i in 1:dim(df)[2]){ i <- ind[,i] name <- paste0("var", i[1], "_", i[2]) val <- names(df)[i[ifelse(sum(df[,i[1]]) > sum(df[,i[2]]),1,2)]] df <- mutate_(df, .dots= setNames(list(val),name)) } If you re ... -
我们可以使用mget来获取list的值 lst <- mget(paste0("a", 1:3)) 然后遍历list并应用该功能 lapply(lst, yourFunction) We can use mget to get the values in a list lst <- mget(paste0("a", 1:3)) and then loop through the list and apply the function lapply(lst, yourFunction)
-
把它变成一个阵列! 使用由数字区分的不同名称是一种不好的做法: int ran[3]; for (int k = 0; k < 3; k++) { ran[k % 3] = k; } 现在,不使用ran1或ran2 ,而是使用ran[1]或ran1 ran[2] 。 C中的数组非常混乱,它们与指针不同。 Make it an array! Using different names differentiated by a number is a bad practice: int ran[3]; ...
-
Python:在for循环中将迭代变量的值添加到变量名称中(Python: Add value of iteration variable to variable name within for loop)[2023-05-19]
解决方案A(推荐): dfs = {} for i in l: dfs["a"+str(i)], dfs["b"+str(i)] = func(df[df.col3 == i]) ... 然后你可以使用这样的数据框: func2(dfs["a1"]) # dfs["a1"] represents func(df[df.col3 == i])'s first return. ... 解决方案B(不推荐) 如果你绝对想使用局部变量,你需要: for i in l: locals()["a" ... -
循环变量名称(Looping over variable names)[2022-10-14]
如果你想迭代那个Grid中的按钮,那么你可以为Grid指定名称,比如buttonsGrid 。 你可以迭代它的儿童财产 foreach (var childButton in buttonsGrid.Children.OfType -
请注意,tbl_df在dplyr库中已被删除。 但你可以很容易地使用data.frame或as.data.frame。 xtable <- data.frame(x1=c(1,2,3), x2=c(3,4,5)) str(xtable) # shows the structure of the data.frame R允许我们轻松执行矢量操作,从而减少了许多循环的需求。 # lapply applies a function to every column in a data.frame xtable < ...
-
虽然这是可能的, 但这不是一个好主意 。 具有动态生成的变量名的代码难以阅读和维护。 也就是说,您可以使用exec函数来执行此操作,该函数从字符串执行代码。 这将允许您使用字符串连接动态构造变量名称。 但是,你真的应该使用字典。 这为您提供了一个具有动态命名键的对象,它更适合您的目的。 例如: import pandas as pd Data = {} for i in range(2010,2017): Data[i] = pd.read_csv("Data_from_" +str(i) + ". ...
-
这条线: vars()[rate] = 'k' + str(i) 必须替换为: vars()['k' + str(i)]=rate The line: vars()[rate] = 'k' + str(i) has to be replaced by: vars()['k' + str(i)]=rate