Adding see_other method to ActionController

303 (See Other) is the status code a resource returns to tell the client about the new resource it just created (typically after a POST). 301/302 is the status code some servers return to tell the browser where to go next. It works because browsers ignore the distinction and treat all three status codes the same way, and few people understand the difference. But when developing an application that uses resources (e.g. using ActiveResource), these status codes have distinct meaning. 303 points to the newly created resource, but 301/302 say "this resource moved, please send your POST again to this new location".

In 2.0 we get the convenience of:

  def create     item = Item.create(params[:item])     redirect_to item, :status=>:see_other   end

Regardless, I think there's a strong argument for adding a see_other method. As syntactic sugar, it will help developers who are not quite aware of the difference between 302 and 303.

Another possibility is changing redirect_to, so it defaults to return 303 whenever it responds to a POST. Do the right thing without bothering the developer with the nuances. I'm not sure that would be enough, though.

Let's try a simple scenario. I have a todo list application, the user creates new items using a form, submits the request and gets redirected back to the todo list. Client applications, on the other hand, make POST requests and expect a 303 pointing them to the new resource.

My controller look likes:

  def create     item = Item.create(params[:item])     respond_to do |format|       format.html { redirect_to items_url }       format.all { see_other item }     end   end

The syntactic sugar helps with the distinction, handling both cases, and distinguishing between the browser's 302 and application's 303.

And we can extract this into a further simplification:

  def create     item = Item.create(params[:item])     see_other item, :html=>items_url   end

Comments?

Assaf

In 2.0 we get the convenience of:

  def create     item = Item.create(params[:item])     redirect_to item, :status=>:see_other   end

Regardless, I think there's a strong argument for adding a see_other method. As syntactic sugar, it will help developers who are not quite aware of the difference between 302 and 303.

I don't think that another method is justified just for this case. there are hundreds of other status codes out there, why don't they get their own methods?

Changing the default behaviour of redirect_to also seems way too risky for the minority of clients (active resource) that can make use of the distinction.

The current API works fine, and the single status argument isn't a huge barrier to overcome.

In 2.0 we get the convenience of:

def create item = Item.create(params[:item]) redirect_to item, :status=>:see_other end

Regardless, I think there’s a strong argument for adding a see_other

method. As syntactic sugar, it will help developers who are not quite aware of the difference between 302 and 303.

I don’t think that another method is justified just for this case. there are hundreds of other status codes out there, why don’t they get

their own methods?

  1. Common use case.
  2. Recommended pattern we should encourage.
  3. Avoid boilerplate code.

And that’s true for a lot of other status codes, many of which already get treatment in Rails. That treatment depends on the context, for example, mapping ActiveRecord exception to 4xx status code is more developer-friendly than catching the exception yourself and calling a method. For 303 it happens to be calling a method.

Assaf

1. Common use case. 2. Recommended pattern we should encourage. 3. Avoid boilerplate code.

And that's true for a lot of other status codes, many of which already get treatment in Rails. That treatment depends on the context, for example, mapping ActiveRecord exception to 4xx status code is more developer-friendly than catching the exception yourself and calling a method. For 303 it happens to be calling a method.

What other status codes get a special method?

Each additional method is something we'll have to support going forward. Something that's easy to add now, gradually becomes harder and harder to support as it picks up users and features. On the whole we're better off not adding a feature till the use case is really compelling, and I'm just not seeing that here.

Michael Koziarski wrote:


1. Common use case.
2. Recommended pattern we should encourage.
3. Avoid boilerplate code.
And that's true for a lot of other status codes, many of which already get
treatment in Rails. That treatment depends on the context, for example,
mapping ActiveRecord exception to 4xx status code is more developer-friendly
than catching the exception yourself and calling a method. For 303 it
happens to be calling a method.

What other status codes get a special method?
Each additional method is something we'll have to support going
forward. Something that's easy to add now, gradually becomes harder
and harder to support as it picks up users and features. On the whole
we're better off not adding a feature till the use case is really
compelling, and I'm just not seeing that here.

According to my sources, the HTTP protocol is not going to change any time soon, so I’m not extending an invitation to go down the slippery slope of polluting core with methods by the boatload. This is a very specific use case, I suggest we treat it as such. The questions we should ask are: is this common enough? and what is the best treatment?

When you’re working strictly with Web browsers, 302 (redirect_to) is good enough, or you can 200 (render). Not so for the programmable Web, which makes a clear distinction between redirect and see other. Rails 2.0 is tackling this sweet spot, with all the work around resources and programmable data formats (XML, JSON), so it’s certainly within scope.

In fact, if you consider ActiveResource part of Rails, then the lack of treatment for 303 is a bug. Have a look at ActiveResource to see how it reacts to redirect_to following a POST. By that measure, we have an expectation to 303 in the framework.

Most of my controllers have a create action, and all of these controllers I expect to expose as RESTful services. If the same is true for other people, then this case is not just specific but also quite common.

In my opinion that’s enough evidence for use to seriously consider how we handle 303 in the framework.

Assaf

When you're working strictly with Web browsers, 302 (redirect_to) is good enough, or you can 200 (render). Not so for the programmable Web, which makes a clear distinction between redirect and see other. Rails 2.0 is tackling this sweet spot, with all the work around resources and programmable data formats (XML, JSON), so it's certainly within scope.

In fact, if you consider ActiveResource part of Rails, then the lack of treatment for 303 is a bug. Have a look at ActiveResource to see how it reacts to redirect_to following a POST. By that measure, we have an expectation to 303 in the framework.

I dunno, there's a fine line between 'rest friendly' and 'worrying about impractical academic differences'. I'm not necessarily hugely opposed to adding a method, but the fact that it's only the two of us in this thread seems to say there's not a lot of appetite for this stuff.

Anyone else have strong views on the matter?

In my opinion that's enough evidence for use to seriously consider how we handle 303 in the framework.

That's why I applied the patch for :status on redirect_to, I'm not denying it deserves thought, just that it doesn't need a method :wink:

After all, it's just a one line method in application.rb if you want it for now.

def see_other(url)   redirect_to url, :status=>:see_other end

In fact, if you consider ActiveResource part of Rails, then the lack of treatment for 303 is a bug. Have a look at ActiveResource to see how it reacts to redirect_to following a POST. By that measure, we have an expectation to 303 in the framework.

I dunno, there's a fine line between 'rest friendly' and 'worrying about impractical academic differences'. I'm not necessarily hugely opposed to adding a method, but the fact that it's only the two of us in this thread seems to say there's not a lot of appetite for this stuff.

Anyone else have strong views on the matter?

I'm all for beefing up ActiveResource's handling for each status code, something is is lacking for all but the most common codes. I also believe in using the status code that more closely describes the result to the user-agent, rather than relying on less specific codes.

This thread started with an example where Assaf asserted that 303 See Other was the most appropriate code to indicate a new resource was successfully created as a result of a POST. I don't agree with this.

The 201 Created HTTP status code's sole purpose is to indicate to the user agent a new resource was created and where it can be located. That's what it was designed for. It would be difficult to argue that *any* 3xx status code is better in *this* particular situation than 201.

(Please note that I'm speaking about ideal status codes for user-agents using a REST API. Browsers are a whole other issue, which I'll chime in on below. I wish that weren't the case, but it is.)

In my opinion that's enough evidence for use to seriously consider how we handle 303 in the framework.

That's why I applied the patch for :status on redirect_to, I'm not denying it deserves thought, just that it doesn't need a method :wink:

I agree, for now. However, I do think it would be a useful convention to use 303 when redirecting a browser after a POST creates a new resource, rather than using 302 as most people do.

While each would result in the same end result with most browser (a redirection to the Location URL) 303 is a closer match and IMHO should be preferred when redirecting a browser after a POST request.

Dan Kubb wrote:

In fact, if you consider ActiveResource part of Rails, then the lack of
treatment for 303 is a bug. Have a look at ActiveResource to see how it
reacts to redirect_to following a POST. By that measure, we have an
expectation to 303 in the framework.

I dunno, there's a fine line between 'rest friendly' and 'worrying
about impractical academic differences'. I'm not necessarily hugely
opposed to adding a method, but the fact that it's only the two of us
in this thread seems to say there's not a lot of appetite for this
stuff.
Anyone else have strong views on the matter?

I'm all for beefing up ActiveResource's handling for each status code,
something is is lacking for all but the most common codes. I also believe
in using the status code that more closely describes the result to the
user-agent, rather than relying on less specific codes.
This thread started with an example where Assaf asserted that 303 See Other
was the most appropriate code to indicate a new resource was successfully
created as a result of a POST. I don't agree with this.
The 201 Created HTTP status code's sole purpose is to indicate to the
user agent a new resource was created and where it can be located.
That's what it was designed for. It would be difficult to argue that
*any* 3xx status code is better in *this* particular situation than 201.
(Please note that I'm speaking about ideal status codes for user-agents
using a REST API. Browsers are a whole other issue, which I'll chime in
on below. I wish that weren't the case, but it is.)

I happen to agree with you. 201 is the more descriptive status code. I went with 303 only because browsers like it, and less specific is also more general purpose (you can use 303 from a PUT). But I am toying with an implementation that uses content-type/method detection, to figure whether it should return 201 or 303.

Assaf

Agreed. This was discussed to some (short) extent a while ago: http://dev.rubyonrails.org/ticket/1923

//jarkko

I agree that 303 See Other is a better status code for POST responses. Though my primary reason for supporting 303 is not because it's more "correct", but because browsers will not prompt the user to resend the POST request if the user clicks on Reload.

I'm not sure whether this warrants adding an extra method. But I do think that at the very least, it should be documented in the API documentation as good practice.

Michael Koziarski wrote:

In my opinion that's enough evidence for use to seriously consider how we
handle 303 in the framework.

That's why I applied the patch for :status on redirect_to, I'm not
denying it deserves thought, just that it doesn't need a method ;)
After all, it's just a one line method in application.rb if you want it for now.
def see_other(url)
redirect_to url, :status=>:see_other
end

First, thanks for the redirect_to patch. I started with that originally. Again because this is a common use case, I figured we need to address it in the framework, and it looked to me like the low hanging fruit is submitting a documentation patch. Documenting this means teaching people that for create actions they can’t use simple redirect_to, but need to use redirect_to in a way that doesn’t redirect the original request to the new resource, by following this pattern.

It took all of one read to realize this smells (I do consider documentation to be part of the code), and decide we better refactor it into a method. Actually it smelled like J2EE, you know that framework where instead of taking a stand and doing the right thing, it asks you to memorize a bunch of patterns and write boilerplate code all over the place?

Assaf

First, thanks for the redirect_to patch. I started with that originally. Again because this is a common use case, I figured we need to address it in the framework, and it looked to me like the low hanging fruit is submitting a documentation patch. Documenting this means teaching people that for create actions they can't use simple redirect_to, but need to use redirect_to in a way that doesn't redirect the original request to the new resource, by following this pattern.

As was mentioned by others, you should really be sending 201, so I'm not even sure this is an issue that merits changing the documentation. I realise browsers don't support 201 but that's why we have respond_to

respond_to do |format|   format.xml { head :created...}   format.html { redirect_to wherever... } end

Seeing that a lot of developers are confused about the status codes, shouldn't the documentation mention the differences between 302, 303 and 201? Or at least link to the appropriate discussion for further information? This sort of documentation doesn't have any impact on the API, and thus won't increase maintenance burden, but it'll make lives for developers a bit easier. POST responses are very common and I think Rails should document recommended practice in a well-defined, central place (the API docs) instead of forcing people to look all over the Internet.

I think that's reasonable...

Also, perhaps redirect_to with an activerecord model could assume a 303?

redirect_to foo_path # 301 redirect_to @foo # 303

The fact that browsers don't redo the post when reloading sounds like a good idea.

I like this suggestion.

I think that's reasonable...

Also, perhaps redirect_to with an activerecord model could assume a 303?

redirect_to foo_path # 301 redirect_to @foo # 303

The fact that browsers don't redo the post when reloading sounds like a good idea.

I like this suggestion.

So do I, seems low impact. Are there any browser support issues we need to consider?