Search code examples
ruby-on-railsrails-upgrade

Migrating from Rails 4 to Rails 5: using ActionDispatch::Request.parameter_parsers and config.middleware


I am currently migrating an app from Rails 4 to Rails 5.

I've encountered the following issue when trying to issue commands such as bundle exec rspec spec:

/Users/me/.rvm/gems/ruby-2.2.2/gems/actionpack-5.1.4/lib/action_dispatch/middleware/stack.rb:35:in `build': undefined method `new' for ActionDispatch::ParamsParser:Module (NoMethodError)
        from /Users/me/.rvm/gems/ruby-2.2.2/gems/actionpack-5.1.4/lib/action_dispatch/middleware/stack.rb:99:in `block in build'
        from /Users/me/.rvm/gems/ruby-2.2.2/gems/actionpack-5.1.4/lib/action_dispatch/middleware/stack.rb:99:in `each'
        from /Users/me/.rvm/gems/ruby-2.2.2/gems/actionpack-5.1.4/lib/action_dispatch/middleware/stack.rb:99:in `inject'
        from /Users/me/.rvm/gems/ruby-2.2.2/gems/actionpack-5.1.4/lib/action_dispatch/middleware/stack.rb:99:in `build'
        from /Users/me/.rvm/gems/ruby-2.2.2/gems/railties-5.1.4/lib/rails/engine.rb:508:in `block in app'
        from /Users/me/.rvm/gems/ruby-2.2.2/gems/railties-5.1.4/lib/rails/engine.rb:504:in `synchronize'
        from /Users/me/.rvm/gems/ruby-2.2.2/gems/railties-5.1.4/lib/rails/engine.rb:504:in `app'
        from /Users/me/.rvm/gems/ruby-2.2.2/gems/railties-5.1.4/lib/rails/application/finisher.rb:45:in `block in <module:Finisher>'
        from /Users/me/.rvm/gems/ruby-2.2.2/gems/railties-5.1.4/lib/rails/initializable.rb:30:in `instance_exec'
        from /Users/me/.rvm/gems/ruby-2.2.2/gems/railties-5.1.4/lib/rails/initializable.rb:30:in `run'
        from /Users/me/.rvm/gems/ruby-2.2.2/gems/railties-5.1.4/lib/rails/initializable.rb:59:in `block in run_initializers'
        from /Users/me/.rvm/rubies/ruby-2.2.2/lib/ruby/2.2.0/tsort.rb:226:in `block in tsort_each'
        from /Users/me/.rvm/rubies/ruby-2.2.2/lib/ruby/2.2.0/tsort.rb:348:in `block (2 levels) in each_strongly_connected_component'
        from /Users/me/.rvm/rubies/ruby-2.2.2/lib/ruby/2.2.0/tsort.rb:429:in `each_strongly_connected_component_from'
        from /Users/me/.rvm/rubies/ruby-2.2.2/lib/ruby/2.2.0/tsort.rb:347:in `block in each_strongly_connected_component'
        from /Users/me/.rvm/rubies/ruby-2.2.2/lib/ruby/2.2.0/tsort.rb:345:in `each'
        from /Users/me/.rvm/rubies/ruby-2.2.2/lib/ruby/2.2.0/tsort.rb:345:in `call'
        from /Users/me/.rvm/rubies/ruby-2.2.2/lib/ruby/2.2.0/tsort.rb:345:in `each_strongly_connected_component'
        from /Users/me/.rvm/rubies/ruby-2.2.2/lib/ruby/2.2.0/tsort.rb:224:in `tsort_each'
        from /Users/me/.rvm/rubies/ruby-2.2.2/lib/ruby/2.2.0/tsort.rb:203:in `tsort_each'
        from /Users/me/.rvm/gems/ruby-2.2.2/gems/railties-5.1.4/lib/rails/initializable.rb:58:in `run_initializers'
        from /Users/me/.rvm/gems/ruby-2.2.2/gems/railties-5.1.4/lib/rails/application.rb:353:in `initialize!'
        from /Users/me/Documents/mikamai/surveyeah/config/environment.rb:5:in `<top (required)>'
        from /Users/me/Documents/mikamai/surveyeah/spec/rails_helper.rb:4:in `require'
        from /Users/me/Documents/mikamai/surveyeah/spec/rails_helper.rb:4:in `<top (required)>'
        from /Users/me/.rvm/gems/ruby-2.2.2/gems/rspec-core-3.7.0/lib/rspec/core/configuration.rb:1455:in `require'
        from /Users/me/.rvm/gems/ruby-2.2.2/gems/rspec-core-3.7.0/lib/rspec/core/configuration.rb:1455:in `block in requires='
        from /Users/me/.rvm/gems/ruby-2.2.2/gems/rspec-core-3.7.0/lib/rspec/core/configuration.rb:1455:in `each'
        from /Users/me/.rvm/gems/ruby-2.2.2/gems/rspec-core-3.7.0/lib/rspec/core/configuration.rb:1455:in `requires='
        from /Users/me/.rvm/gems/ruby-2.2.2/gems/rspec-core-3.7.0/lib/rspec/core/configuration_options.rb:112:in `block in process_options_into'
        from /Users/me/.rvm/gems/ruby-2.2.2/gems/rspec-core-3.7.0/lib/rspec/core/configuration_options.rb:111:in `each'
        from /Users/me/.rvm/gems/ruby-2.2.2/gems/rspec-core-3.7.0/lib/rspec/core/configuration_options.rb:111:in `process_options_into'
        from /Users/me/.rvm/gems/ruby-2.2.2/gems/rspec-core-3.7.0/lib/rspec/core/configuration_options.rb:21:in `configure'
        from /Users/me/.rvm/gems/ruby-2.2.2/gems/rspec-core-3.7.0/lib/rspec/core/runner.rb:99:in `setup'
        from /Users/me/.rvm/gems/ruby-2.2.2/gems/rspec-core-3.7.0/lib/rspec/core/runner.rb:86:in `run'
        from /Users/me/.rvm/gems/ruby-2.2.2/gems/rspec-core-3.7.0/lib/rspec/core/runner.rb:71:in `run'
        from /Users/me/.rvm/gems/ruby-2.2.2/gems/rspec-core-3.7.0/lib/rspec/core/runner.rb:45:in `invoke'
        from /Users/me/.rvm/gems/ruby-2.2.2/gems/rspec-core-3.7.0/exe/rspec:4:in `<top (required)>'
        from /Users/me/.rvm/gems/ruby-2.2.2/bin/rspec:23:in `load'
        from /Users/me/.rvm/gems/ruby-2.2.2/bin/rspec:23:in `<main>'
        from /Users/me/.rvm/gems/ruby-2.2.2/bin/ruby_executable_hooks:15:in `eval'
        from /Users/me/.rvm/gems/ruby-2.2.2/bin/ruby_executable_hooks:15:in `<main>'

I think the issue comes from the file application.rb which contains:

module MyApp
  class Application < Rails::Application

    config.middleware.insert_before ActionDispatch::ParamsParser, 'CatchJsonParseErrors'

  end
end

I've tried to change that line to:

module MyApp
  class Application < Rails::Application

    config.middleware.use ActionDispatch::ParamsParser, 'CatchJsonParseErrors'

  end
end

but it hasn't fixed things. I took a look at the Rails 5 release notes and it seems that

ActionDispatch::ParamsParser is deprecated and was removed from the middleware stack. To configure the parameter parsers use ActionDispatch::Request.parameter_parsers=.

although I'm not sure how I'd use that.

The app/middleware/catch_json_parse_errors.rb file looks like this:

class CatchJsonParseErrors
  def initialize(app)
    @app = app
  end

  def call(env)
    begin
      @app.call(env)
    rescue ActionDispatch::ParamsParser::ParseError => error
      if env['HTTP_ACCEPT'] =~ /application\/json/
        error_output = "There was a problem in the JSON you submitted: #{error}"
        return [
          400, { "Content-Type" => "application/json" },
          [ { status: 400, error: error_output }.to_json ]
        ]
      else
        raise error
      end
    end
  end
end

Anyone know how I'd update this middleware configuration for Rails 5? Any help much appreciated! :D thanks in advance


Solution

  • Fixed this with:

    module MyApp
      class Application < Rails::Application
    
        require './lib/middleware/catch_json_parse_errors.rb'
        config.middleware.insert_before Rack::Head, CatchJsonParseErrors
    
      end
    end
    

    and my lib/middleware/catch_json_parse_errors.rb:

    class CatchJsonParseErrors
      def initialize(app)
        @app = app
      end
    
      def call(env)
        begin
          @app.call(env)
        rescue ActionDispatch::Http::Parameters::ParseError => error
          if env['HTTP_ACCEPT'] =~ /application\/json/
            error_output = "There was a problem in the JSON you submitted: #{error}"
            return [
              400, { "Content-Type" => "application/json" },
              [ { status: 400, error: error_output }.to_json ]
            ]
          else
            raise error
          end
        end
      end
    end
    

    notice how I also had to change from ActionDispatch::ParamsParser::ParseError to ActionDispatch::Http::Parameters::ParseError here. There's probably a nicer way to load middleware files in ./lib/middleware/ but this works for now.