1

我正在关注来自 PeepCode 的(现在稍微过时的)Meet Rails 3教程,并且在获取教程的一些建议以与 Rails 3.2 一起使用时遇到了麻烦。

本教程让您创建一个Role属于 a 的模型Project

class Role < ActiveRecord::Base
  belongs_to :project
  validates :project_id, :presence => true
  attr_protected :project_id
end

routes.rb文件嵌套了资源,因此Role您必须在 aRole的上下文中使用 a Project

resources :projects do
  resources :roles
end

请注意,在上面的模型代码中,本教程建议您使用attr_protected来保护该:project_id字段,因为可以通过Role在项目的上下文中创建 every 来“更安全地”设置它,就像在roles_controller.rb中这样:

class RolesController < ApplicationController
  ⋮

  def create
    @role = project.roles.new(params[:role])
    ⋮

Role问题是,使用Formtastic创建的用于创建 的 HTML 表单包含一个project_id用于选择项目的字段。因此,当project.roles.new(params[:role])尝试使用表单中的参数来填充新Role对象时,它会尝试设置project_id使用质量分配,但失败并显示:

ActiveModel::MassAssignmentSecurity::RolesController#create 中的错误
无法批量分配受保护的属性:project_id

实现这一点的公认方法是什么?保护project_id属性是个坏主意吗?或者有没有办法Role用表单数据填充新的而不包括project_id

4

1 回答 1

0

如果你是project通过params[:project_id]而不是params[:role][:project_id]你实际上可能会设置冲突的值。

Mass Assignment 想要保护这一点的原因是防止用户输入任意值,因为project_id这可能允许project不受此用户控制的 a。你有几个选择。

如果您有授权useraccount附加到对象,您可以添加before_save回调,例如self.project_id = nil unless user.projects.find(project_id).

既然你不这样做,我会使用project_idfrom hash 来查找项目,然后回退到路由 id(我不确定它是否会project_id或只是id在我的脑海中)。

def create
  user.
    projects.
    find(params[:role].delete(:project_id) || params[:project_id] || params[:id]).
    create(params[:role])

最简单的方法是从表单中删除选择框,因为他们在选择创建新角色时选择了一个项目——它是一个嵌套资源。

于 2013-01-31T06:50:25.703 回答