I was not saying that it wasn't possible to write the proper routes, just that they don't seem very consistent.

I would guess that most applications won't be API ones, so many of them won't opt for REST and responds_to.

For example, all applications I've been working with for the past decade will only need to respond to a single format per action.

That means that if I wanted strict rules to my routes I'd have to write them as:

get '/anything', format: false

or

get '/anything.:format' => 'anything#index', constraints: {format: /json/}, defaults: {format: :json}

I could use a block for this common option except that not all of my actions will return a JSON.

Sometimes I'll just return a "head :ok" for remove actions, for example.

But it is important that Rails always returns the correct content-type so that my AJAX callbacks get interpreted correctly.

The only reason I have something like '/anything.json' in some of my actions is because I want to cache some of them.

Today is Mother's day in Brazil and I'm going to leave in a few minutes to have lunch with my mom in a near city, but I guess I've already found some bugs.

Consider this snippets:

class TestController < ApplicationController
  caches_action :index

  def index
    render json: 'test' #, content_type: 'application/json'
  end

  def expire
    expire_action :index #action: :index #, format: :json
    head :ok
  end
end

routes.rb:

get "test/index", format: false, as: :index
# get "test/index" => 'test#index', format: false, defaults: {format: :json}, as: :index
get "test/expire"

I've made several experiments that yield to strange results when it comes to content-type.

Basically, I'm getting 'text/html' instead of 'application/json'. This happens even if I pass content_type: 'application/json' explicitly.

Another bug is that expire_action doesn't seem to work correctly either. For example, if you use the commented route the output will be:

Expire fragment views/localhost:3000/assets?controller=test

It doesn't matter if I use a named route or "expire_action action: :index" or "expire_action action: :index, format: :json" if I remember correctly.

Sorry, I have to leave now and I'll only be back very late at night.

Have a great Sunday,

Rodrigo.

Em 13-05-2012 06:10, Andrew White escreveu:
On 13 May 2012, at 04:10, Rodrigo Rosenfeld Rosas wrote:

What I was suggesting is that we changed the generated routes.rb so that the 
Rails 1 style route could be written as

match ':controller(/:action(/:id))'
Whether you write it with or without :format it ends up being the same route - 
the mapper checks for the presence of the :format key in the path. The 
generator adds the :format to make it explicitly visible what's happening.

Some history on why there's an optional format would probably useful here. We 
used to generate both formatted routes and non-formatted routes, e.g. you'd 
have formatted_product_path(@product, :json) and product_path(@product). Upon 
investigation[1][2] it was discovered that this took up significant amount of 
memory and was changed to an optional segment[3] in the Rails 2.3 release.

As well as mentioning and explaining the "format" option, like some of these 
examples:

post '/products/:id.:format' =>  'products#show', as: :field, constraints: {id: 
/\d+/} # format is required
post '/products/:id' =>  'products#show', format: true, as: :field, 
constraints: {id: /\d+/} # this is equivalent
post '/products/:id.json' =>  'products#show', format: :json # it only answers 
to json format
post '/products/:id' =>  'products#show', format: :json # the same with a 
shorter URL but still allowing you to cache the result and use the correct 
content-type

But then I decided to test it and I was surprised that it doesn't make any 
difference if you use caches_page.
Also, there are more weird rules with regards to page or action caching. The 
routes rules don't seem to be respected if you use caching.

Consider this example:

get '/products' =>  'products#list', format: :json

try to GET /products with caches_page enabled and you won't get a 
'application/json' content-type in the next responses because it won't probably 
even read the routes rules.
Page caching is explicitly designed to avoid hitting the Rails stack - you need 
to setup Apache or nginx to serve the cached files from the format-less path 
with the appropriate content type. Action caching should just avoid the page 
rendering - if you can reproduce a case where a JSON request is action cached 
and returns an incorrect content type when serving the cached file then please 
create a new issue in the tracker.

Also, if you GET /products.html not only it accepts this request but the 
content-type will be 'text/html' instead of 'application/json' (independent 
from caching).
That's because you're defining a default format for the route not a constraint 
- either use a explicit constraint or use a regexp, e.g:

   get '/products' =>  'products#list', :format =>  /json/

or

   get '/products' =>  'products#list', :constraints =>  { :format =>  'json' }

The mapper assumes non-significant keys in a route definition are defaults 
unless they're regexps.

Also, consider this other example:

get '/products.json' =>  'products#list', format: :json

This will also respond to '/products.json.html' for example, and I don't think 
it should answer to anything else but '/products.json'. Also, the content-type 
declared in the routes wouldn't be respected.
That's because :format is still being appended to the route - the mapper 
doesn't interpret the path you specify other than to look for segment keys and 
optional segments. If you're after a format-less path that only serves JSON 
then use this:

   get '/products' =>  'products#list', :format =>  false, :defaults =>  { :format 
=>  'json' }

or if you want the extension then use this:

   get '/products.json' =>  'products#list', :format =>  false, :defaults =>  { 
:format =>  'json' }

The only way to turn off the :format segment being added is to either insert it 
yourself or pass :format =>  false.

Maybe I'm the only one considering the current behavior an issue, but I'd like 
to ask you to consider some changes in the routing rules with regards to format 
to make them less loose.
If you can come up with a route that isn't supported or doesn't appear to be 
supported please open a new issue. You don't need to ping me on it - I normally 
take a look at all the routing issues that get created.


Andrew White

[1]: https://rails.lighthouseapp.com/projects/8994/tickets/1215
[2]: https://rails.lighthouseapp.com/projects/8994/tickets/1359
[3]: 
https://github.com/rails/rails/commit/fef6c32afe2276dffa0347e25808a86e7a101af1


--
You received this message because you are subscribed to the Google Groups "Ruby on 
Rails: Core" group.
To post to this group, send email to [email protected].
To unsubscribe from this group, send email to 
[email protected].
For more options, visit this group at 
http://groups.google.com/group/rubyonrails-core?hl=en.

Reply via email to