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?