【问题标题】:Can I set a nested attribute in the controller vs. the view我可以在控制器与视图中设置嵌套属性吗
【发布时间】:2012-08-11 20:42:19
【问题描述】:

我有一个简单的嵌套表单,我正在设置一个带有隐藏字段的嵌套属性:

<%= role_form.hidden_field :company_id, :value => session[:company_id] %>

这里的想法是我通过当前会话变量设置的company_id 将这个嵌套模型(基于角色的权限系统)关联到另一个模型Company。我的问题是用户可以发送请求并使用任意company_id 创建/更新角色并获得对另一家公司帐户的访问权限。

我可以强制嵌套模型属性成为此会话值或验证吗?

我正在考虑创建:

@user = User.new(params[:user])
@user.roles.first.company_id = session[:company_id]

对于更新,我可以做同样的事情。

至于我尝试的验证:

accepts_nested_attributes_for :roles, :limit => 1, :allow_destroy => true , :reject_if => proc { |attributes| attributes['company_id'] != session[:company_id] }

但您似乎无法访问模型中的会话信息。

有人知道我是否可以通过这两种方式做到这一点?

【问题讨论】:

    标签: ruby-on-rails-3 nested-attributes


    【解决方案1】:

    与其将 company_id 存储在 session 中,不如向 company 添加一个随机生成的 token 列,并通过 Company.find_by_token(session[:token]) 获取 id。如果你看this Railscast on authentication中的current_user方法是怎么做的,也是一样的思路。

    编辑: 对不起,我误解了你的问题。您的视图中根本不应该有隐藏的 company_id 字段。您应该在创建方法中手动设置它:

    @user = User.new(params[:user])
    @user.company_id = session[:company_id]
    

    您可以保护 company_id 免受用户更改输入名称的影响,方法是保护 company_id 免受模型中的批量分配:

    attr_protected :company_id
    

    请参阅rails guide on mass assignment protection 了解更多信息。注意:更常见的解决方案是这样的:

    class ApplicationController < ActionController::Base
    
      protect_from_forgery
    
      def current_company
        @current_company ||= Company.find_by_auth_token!(cookies[:auth_token]) if cookies[:auth_token]
      end
    end
    
    class User < ApplicationController
      def create
        @user = current_company.users.build(params[:user])
      end
    end
    

    更新 2:

    因此,您正在创建一个用户和一个角色,并希望对它们进行单独验证,这应该可以满足您的需求。

    role_params = params[:user].delete :role # Change to the appropriate symbol for your form
    @user = User.new(params[:user])
    role = @user.roles.build(role_params)
    role.company_id = session[:company_id]
    
    if(@user.save and role.user_id = @user.id and role.save) # Might want to just check for valid instead of trying to save
    ...
    

    【讨论】:

    • 感谢您的提示。这可能是一个好主意,但这仍然不能解决我的问题。目前,用户可以批量分配另一个 company_id 并访问另一个公司的帐户。这不太可能发生,我只是将其视为一个明显的安全漏洞。
    • 我已经更新了我的答案,以便更恰当地回答您的问题。看起来您正在尝试在质量分配保护方面重新发明*,因为它已经内置在轨道中!给出了如何处理这个问题的例子,以及关于这个主题的官方 Rails 指南的链接。
    • 好的。我明白你在说什么。我实际上在这个应用程序中使用了那个 Railscast。我认为 attr_protected 是我的解决方案。剩下的问题是 company_id 不是在用户上设置的,而是在嵌套角色上设置的。我有一个系统,其中单个用户登录(电子邮件)可以通过角色访问多个公司模型。每个角色都有一个 user_id 和一个 company_id。 user_id 以嵌套形式自动设置,但我需要手动设置 company_id。我不知道如何做到这一点,因为 accept_nested_attributes 似乎是通过魔法做到的。
    • 这是另一个帖子*.com/questions/3011479/…,似乎在类似的线程上。合并调用可能是答案,但在我的情况下,我需要验证/更新嵌套表单的 params(:role) 数据。
    • 你用同样的方式做,只是有 attr_protected on 角色,并通过控制器设置它——@user.roles.first 或者你选择角色 .company_id = session[: company_id]。您可能还需要考虑从单独的页面更新用户和角色表,以便更精细地控制。
    最近更新 更多