Rails: parameters with dots in routes behave differently in Rails 5

Created on 27 Apr 2017  路  1Comment  路  Source: rails/rails

Seems that a bug was introduced in Rails 5. When we want to support dots in routes then the format is also set, even if the format is already part of a parameter.

Steps to reproduce

I have the following route:

controller 'my_files' do
  get 'my_files/:my_file' => :show, as: 'my_file', constraints: { my_file: %r{[^\/]+} }
end

And then I introduce urls like:

http://localhost:3000/my_files/ana.rb

http://localhost:3000/my_files/ana.json

Expected behavior

The expected behavior and what actually happens in Rails 4.2.7.1 is that both urls work. Both include the file extension as part of the my_file attribute and the request format is html. This is the expected as behavior, as if the extension is part of the parameter it doesn't make sense that it is used for format too.

Actual behavior

In Rails 5 and Rails 5.0.1 only the first url work. The second fails with

MyFilesController#show is missing a template for this request format and variant. request.formats: ["application/json"] request.variant: []

In this case the request format is json, although my_file is set to ana.json, which already includes the extension.

System configuration

Rails version
As said it works with Rails 4.2.7.1 and it doesn't work with Rails 5 and Rails 5.0.1, so seems that the behaviour changed in Rails 5.

Ruby version

I tested it with ruby 2.4.1 and ruby 2.2.5


I think it is a bug and that should be fixed to keep the behavior of Rails 4. In case that is not, it is an important change and should be documented, and currently it is not. Also, another way to address the same behavior should be provided. Is there currently another way to do this? :confounded:

I set a simple project to test this in the two Rails version that I can share if needed.

actionpack routing

Most helpful comment

@Ana06 this change was part of #20831 which was required for the new API application feature in Rails 5.0, previous to this the path parameter :format was nil and it was falling through to the default format of text/html. In this case it's better to be explicit, so turn off the :format path parameter and provide an explicit default of html so that it doesn't use the path, e.g:

scope format: false do
  defaults format: 'html' do
    constraints my_file: %r{[^\/]+} do
      get 'my_files/:my_file', to: 'my_files#show', as: 'my_file'
    end
  end
end

You can write that in a single route if want by like this:

get 'my_files/:my_file',
  to: 'my_files#show',
  as: 'my_file',
  format: false,
  defaults: { format: 'html' },
  constraints: { my_file: %r{[^\/]+} }

Sorry that it broke your application but the change is for the better.

>All comments

@Ana06 this change was part of #20831 which was required for the new API application feature in Rails 5.0, previous to this the path parameter :format was nil and it was falling through to the default format of text/html. In this case it's better to be explicit, so turn off the :format path parameter and provide an explicit default of html so that it doesn't use the path, e.g:

scope format: false do
  defaults format: 'html' do
    constraints my_file: %r{[^\/]+} do
      get 'my_files/:my_file', to: 'my_files#show', as: 'my_file'
    end
  end
end

You can write that in a single route if want by like this:

get 'my_files/:my_file',
  to: 'my_files#show',
  as: 'my_file',
  format: false,
  defaults: { format: 'html' },
  constraints: { my_file: %r{[^\/]+} }

Sorry that it broke your application but the change is for the better.

Was this page helpful?
0 / 5 - 0 ratings