新手问题 一个关于 mass-asign 的问题,设计到一点如何 design 对象关系

evil850209 · 2013年03月19日 · 最后由 lulalala 回复于 2013年10月15日 · 2896 次阅读

写了一个 rails 的 demo 项目。用了一个 devise 的 User 的 model,和一个 project model。在 project 中有一个 owner_id 列,通过外键的定义和 User 关联了。

在创建 project 时,遇到了 mass-asign 的问题了,owner_id 不能被赋值。


class Project < ActiveRecord::Base
  belongs_to :owner, :class_name => 'User', :foreign_key => :owner_id
  attr_accessible :deadline, :description, :name, :owner, :status
  validates_presence_of :name, :owner, :deadline
  self.per_page = 5
end

第一个问题是,这里可以把 owner_id 加到 attr_accessible 中吗?这样设计是否有问题?

第二个问题是,我在 controller 中做了一下处理

private
  def project_params
    owner_id = params[:project].delete(:owner_id)
    owner = User.find(owner_id) unless owner_id.blank?
    params[:project][:owner] = owner
    params[:project]
  end

但当我引用 cancan 那个 gem 后,出现了这个异常:

load_and_authorize_resource

Can't mass-assign protected attributes: owner_id

process_removed_attributes(gem) activemodel-3.2.12/lib/active_model/mass_assignment_security/sanitizer.rb

class StrictSanitizer < Sanitizer
          def process_removed_attributes(attrs)
            return if (attrs - insensitive_attributes).empty?
            raise ActiveModel::MassAssignmentSecurity::Error, "Can't mass-assign protected attributes: #{attrs.join(', ')}"
          end

          def insensitive_attributes
            ['id']
          end

我现在不用 attr_accessible 了,用 gem 'strong_parameters',Rails 4 内置。

@Rei 能说的稍微详细些吗? :)

https://github.com/rails/strong_parameters

把参数过滤放到 Action,这个插件是 Rails 核心小组维护的。

那如果我将 owner_id 放到 attr_accessible 这种设计是否正确呢?总感觉有隐患。

@Rei 用这个插件需要将所有需要赋值的属性都列出来,相对于 attr_accessible 优势和好处在哪里呢?

@Rei 换成 strong_parameters 还是有问题,cancan 引用时报错


load_and_authorize_resource

def project_params
    params.require(:project).permit(:name, :description, :deadline, :owner_id, :status)
end

ActiveModel::ForbiddenAttributes at /projects ActiveModel::ForbiddenAttributes

sanitize_for_mass_assignment(gem) strong_parameters-0.2.0/lib/active_model/forbidden_attributes_protection.rb

     def sanitize_for_mass_assignment(*options)
       new_attributes = options.first
       if !new_attributes.respond_to?(:permitted?) || new_attributes.permitted?
         super
      else
        raise ActiveModel::ForbiddenAttributes
      end
    end
  end
end

load_and_authorize_resource 會自動幫你創造一個 model obj,但是沒有經過 strong parameter 確認,所以會導致你說的錯誤。目前 cancan 還沒有相關對策,只能不要自動作 loading(在 create action 使用 authorize_resource)

把 owner_id 放在 attr_accessible 的確可能導致漏洞。所以通常會把 owner_id 從 param hash 移掉,作檢查再獨自 assign 到 model 裡面。

需要 登录 后方可回复, 如果你还没有账号请点击这里 注册