首页 \ 问答 \ CanCanCan和ForbiddenAttributesError(CanCanCan and ForbiddenAttributesError)

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
更新时间:2022-08-22 06:08

最满意答案

把你的轴放在一个列表中:

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]} 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 ...
  • 如果你真的想使用循环,你可以尝试: 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]; ...
  • 解决方案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" ...
  • 如果你想迭代那个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

最新问答

更多
  • 您如何使用git diff文件,并将其应用于同一存储库的副本的本地分支?(How do you take a git diff file, and apply it to a local branch that is a copy of the same repository?)
  • 将长浮点值剪切为2个小数点并复制到字符数组(Cut Long Float Value to 2 decimal points and copy to Character Array)
  • OctoberCMS侧边栏不呈现(OctoberCMS Sidebar not rendering)
  • 页面加载后对象是否有资格进行垃圾回收?(Are objects eligible for garbage collection after the page loads?)
  • codeigniter中的语言不能按预期工作(language in codeigniter doesn' t work as expected)
  • 在计算机拍照在哪里进入
  • 使用cin.get()从c ++中的输入流中丢弃不需要的字符(Using cin.get() to discard unwanted characters from the input stream in c++)
  • No for循环将在for循环中运行。(No for loop will run inside for loop. Testing for primes)
  • 单页应用程序:页面重新加载(Single Page Application: page reload)
  • 在循环中选择具有相似模式的列名称(Selecting Column Name With Similar Pattern in a Loop)
  • System.StackOverflow错误(System.StackOverflow error)
  • KnockoutJS未在嵌套模板上应用beforeRemove和afterAdd(KnockoutJS not applying beforeRemove and afterAdd on nested templates)
  • 散列包括方法和/或嵌套属性(Hash include methods and/or nested attributes)
  • android - 如何避免使用Samsung RFS文件系统延迟/冻结?(android - how to avoid lag/freezes with Samsung RFS filesystem?)
  • TensorFlow:基于索引列表创建新张量(TensorFlow: Create a new tensor based on list of indices)
  • 企业安全培训的各项内容
  • 错误:RPC失败;(error: RPC failed; curl transfer closed with outstanding read data remaining)
  • C#类名中允许哪些字符?(What characters are allowed in C# class name?)
  • NumPy:将int64值存储在np.array中并使用dtype float64并将其转换回整数是否安全?(NumPy: Is it safe to store an int64 value in an np.array with dtype float64 and later convert it back to integer?)
  • 注销后如何隐藏导航portlet?(How to hide navigation portlet after logout?)
  • 将多个行和可变行移动到列(moving multiple and variable rows to columns)
  • 提交表单时忽略基础href,而不使用Javascript(ignore base href when submitting form, without using Javascript)
  • 对setOnInfoWindowClickListener的意图(Intent on setOnInfoWindowClickListener)
  • Angular $资源不会改变方法(Angular $resource doesn't change method)
  • 在Angular 5中不是一个函数(is not a function in Angular 5)
  • 如何配置Composite C1以将.m和桌面作为同一站点提供服务(How to configure Composite C1 to serve .m and desktop as the same site)
  • 不适用:悬停在悬停时:在元素之前[复制](Don't apply :hover when hovering on :before element [duplicate])
  • 常见的python rpc和cli接口(Common python rpc and cli interface)
  • Mysql DB单个字段匹配多个其他字段(Mysql DB single field matching to multiple other fields)
  • 产品页面上的Magento Up出售对齐问题(Magento Up sell alignment issue on the products page)