Rails Rail4 中,当在 params 中包含上传文件属性的时候,内嵌属性将不会被 strong parameter 正常处理

simonykq · 2014年11月09日 · 2173 次阅读

在公司的一个项目中,无意中发现了 Rails 的这个 bug。

如果 params 属性不包含上传文件,一切嵌套属性表现正常。但是当 params 中包含文件的时候(multipart 请求),嵌套属性将出现问题,请参看以下测试代码

unless File.exist?('Gemfile')
  File.write('Gemfile', <<-GEMFILE)
    source 'https://rubygems.org'
    gem 'rails', path: '~/code/rails'
    gem 'arel', github: 'rails/arel'
    gem 'rack', github: 'rack/rack'
    gem 'i18n', github: 'svenfuchs/i18n'
  GEMFILE

  system 'bundle'
end

require 'bundler'
Bundler.setup(:default)

require 'rails'
require 'action_controller/railtie'

require 'yaml'

class TestApp < Rails::Application
  config.root = File.dirname(__FILE__)
  config.session_store :cookie_store, key: 'cookie_store_key'
  config.secret_token    = 'secret_token'
  config.secret_key_base = 'secret_key_base'

  config.logger = Logger.new($stdout)
  Rails.logger  = config.logger

  routes.draw do
    post '/' => 'test#test'
  end
end

class TestController < ActionController::Base
  include Rails.application.routes.url_helpers

  def test
    render json: my_params
  end

  private
  def my_params
    params.require(:thing).permit(
      # :some_file,
      :some_scalar_attribute,
      :some_array_of_scalars  => [],
      :some_array_of_hashes_containing_scalars => [:scalar_one, :scalar_two]
    )
  end
end

require 'minitest/autorun'
require 'rack/test'

class BugTest < Minitest::Test
  include Rack::Test::Methods

  POST_DATA = {
    "thing" => {
      "some_file" => Rack::Test::UploadedFile.new(File.open(File.join(Rails.root, 'myfile.csv'))),
      "some_scalar_attribute" => "foo",
      "some_array_of_scalars" => ["b", "c"],
      "some_array_of_hashes_containing_scalars" => [
        {"scalar_one" => "d", "scalar_two" => "e"},
        {"scalar_one" => "f", "scalar_two" => "g"}
      ]
    }
  }

  JSON_DATA = '{"some_scalar_attribute":"foo","some_array_of_scalars":["b","c"],"some_array_of_hashes_containing_scalars":[{"scalar_one":"d","scalar_two":"e"},{"scalar_one":"f","scalar_two":"g"}]}'

  def test_returns_success
    post '/', POST_DATA
    assert last_response.ok?
    assert_equal JSON_DATA, last_response.body
  end

  private
    def app
      Rails.application
    end
end

用 Ruby 的 mini test 测试此代码之后,测试将显示不通过。这里,我往 Rails 的 controller POST 了一个"some_array_of_hashes_containing_scalars"属性。它是一个 array of hash(杂凑数组)。当 Rails 接受到此杂凑数组的时候,params["some_array_of_hashes_containing_scalars"] 只接受到了数组中的最后一个杂凑,之前的杂凑都莫名其妙的被 Rails 过滤掉了。而当在 POST_DATA 中删除/注释掉“some_file”属性之后,测试通过。一切正常!

暂无回复。
需要 登录 后方可回复, 如果你还没有账号请 注册新账号