使用受保护的ID属性创建嵌套资源的方法

时间:2013-01-31 05:35:09

标签: ruby-on-rails-3.2 formtastic

我正在关注PeepCode的(现在稍微过时的)Meet Rails 3教程,并且无法获得与Rails 3.2一起使用的一些教程建议。

本教程让您创建属于Role的<{1}}模型:

Project

routes.rb 文件会嵌套class Role < ActiveRecord::Base belongs_to :project validates :project_id, :presence => true attr_protected :project_id end 个资源,因此您必须在Role的上下文中使用Role

Project

请注意,在上面的模型代码中,教程建议您使用resources :projects do resources :roles end 来保护attr_protected字段,因为可以通过创建:project_id中的每个Role来“更安全地”设置它。项目的上下文,如 roles_controller.rb

中的内容
class RolesController < ApplicationController
  ⋮

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

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

  

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

实施此方法的可接受方式是什么?保护project_id属性是个坏主意吗?或者是否有某种方法可以使用表单数据填充新Role而不包括project_id

1 个答案:

答案 0 :(得分:0)

如果您通过project而不是params[:project_id]获得params[:role][:project_id],那么无论如何您实际上都可以设置相互冲突的值。

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

如果您在对象上附加了useraccount,则可以添加before_save回调,例如self.project_id = nil unless user.projects.find(project_id)

既然你没有,我会使用哈希中的project_id来查找项目,然后回到路由ID(我不确定它是project_id还是只是id我的头顶。)

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

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