New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Lock down new `ImplicitRender` behavior for 5.0 RC #23827

Merged
merged 1 commit into from Feb 25, 2016

Conversation

Projects
None yet
7 participants
@chancancode
Member

chancancode commented Feb 23, 2016

  1. Conceptually revert #20276

    The feature was implemented for the responders gem. In the end,
    they did not need that feature, and have found a better fix (see
    plataformatec/responders#131).

    ImplicitRender is the place where Rails specifies our default
    policies for the case where the user did not explicitly tell us
    what to render, essentially describing a set of heuristics. If
    the gem (or the user) knows exactly what they want, they could
    just perform the correct render to avoid falling through to
    here, as responders did (the user called respond_with).

    Reverting the patch allows us to avoid exploding the complexity
    and defining “the fallback for a fallback” policies.

  2. respond_to and templates are considered exhaustive enumerations

    If the user specified a list of formats/variants in a respond_to
    block, anything that is not explicitly included should result
    in an UnknownFormat error (which is then caught upstream to
    mean “406 Not Acceptable” by default). This is already how it
    works before this commit.

    Same goes for templates – if the user defined a set of templates
    (usually in the file system), that set is now considered exhaustive,
    which means that “missing” templates are considered UnknownFormat
    errors (406).

  3. To keep API endpoints simple, the implicit render behavior for
    actions with no templates defined at all (regardless of formats,
    locales, variants, etc) are defaulted to “204 No Content”. This
    is a strictly narrower version of the feature landed in #19036 and
    #19377.

  4. To avoid confusion when interacting in the browser, these actions
    will raise a TemplateMissing error for “interactive” requests
    instead. (The precise definition of “interactive” requests might
    change – the spirit here is to give helpful messages and avoid
    confusions.)

Closes #20666, #23062, #23077, #23564

[Godfrey Chan, Jon Moss, Mike Clark, Matthew Draper, Kasper Timm Hansen]


TODO:

  • Finish porting the new tests in the other PRs
  • Write helpful error messages for the two "no templates" scenario

@chancancode chancancode added this to the 5.0.0 milestone Feb 23, 2016

@kaspth kaspth self-assigned this Feb 23, 2016

@maclover7

This comment has been minimized.

Show comment
Hide comment
@maclover7

maclover7 Feb 24, 2016

Member

Taking the baton from @kaspth, and doing some additions to this.

r? @maclover7

Member

maclover7 commented Feb 24, 2016

Taking the baton from @kaspth, and doing some additions to this.

r? @maclover7

@rails-bot rails-bot assigned maclover7 and unassigned kaspth Feb 24, 2016

@maclover7

This comment has been minimized.

Show comment
Hide comment
@maclover7

maclover7 Feb 24, 2016

Member

Pushed up a commit with some changes. Feel free to squash down -- only pushed up a separate commit so that way others can review.

Passing the baton back to @chancancode for the finale 😄

r? @chancancode

Member

maclover7 commented Feb 24, 2016

Pushed up a commit with some changes. Feel free to squash down -- only pushed up a separate commit so that way others can review.

Passing the baton back to @chancancode for the finale 😄

r? @chancancode

@rails-bot rails-bot assigned chancancode and unassigned maclover7 Feb 24, 2016

@chancancode chancancode changed the title from [WIP] Lock down new `ImplicitRender` behavior for 5.0 RC to Lock down new `ImplicitRender` behavior for 5.0 RC Feb 24, 2016

Lock down new `ImplicitRender` behavior for 5.0 RC
1. Conceptually revert #20276

   The feature was implemented for the `responders` gem. In the end,
   they did not need that feature, and have found a better fix (see
   plataformatec/responders#131).

   `ImplicitRender` is the place where Rails specifies our default
   policies for the case where the user did not explicitly tell us
   what to render, essentially describing a set of heuristics. If
   the gem (or the user) knows exactly what they want, they could
   just perform the correct `render` to avoid falling through to
   here, as `responders` did (the user called `respond_with`).

   Reverting the patch allows us to avoid exploding the complexity
   and defining “the fallback for a fallback” policies.

2. `respond_to` and templates are considered exhaustive enumerations

   If the user specified a list of formats/variants in a `respond_to`
   block, anything that is not explicitly included should result
   in an `UnknownFormat` error (which is then caught upstream to
   mean “406 Not Acceptable” by default). This is already how it
   works before this commit.

   Same goes for templates – if the user defined a set of templates
   (usually in the file system), that set is now considered exhaustive,
   which means that “missing” templates are considered `UnknownFormat`
   errors (406).

3. To keep API endpoints simple, the implicit render behavior for
   actions with no templates defined at all (regardless of formats,
   locales, variants, etc) are defaulted to “204 No Content”. This
   is a strictly narrower version of the feature landed in #19036 and
   #19377.

4. To avoid confusion when interacting in the browser, these actions
   will raise an `UnknownFormat` error for “interactive” requests
   instead. (The precise definition of “interactive” requests might
   change – the spirit here is to give helpful messages and avoid
   confusions.)

Closes #20666, #23062, #23077, #23564

[Godfrey Chan, Jon Moss, Kasper Timm Hansen, Mike Clark, Matthew Draper]
logger.info "No template found for #{self.class.name}\##{action_name}, rendering head :no_content" if logger
super
elsif any_templates?(action_name.to_s, _prefixes)
message = "#{self.class.name}\##{action_name} does not know how to repond " \

This comment has been minimized.

@kaspth

kaspth Feb 25, 2016

Member

repond

@kaspth

kaspth Feb 25, 2016

Member

repond

@@ -256,6 +256,12 @@ Please refer to the [Changelog][action-pack] for detailed changes.
* Rails will only generate "weak", instead of strong ETags.
([Pull Request](https://github.com/rails/rails/pull/17573))
* Controller actions without an explicit `render` call and with no
corresponding templates will render `head :no_conten` implicitly

This comment has been minimized.

@kaspth

kaspth Feb 25, 2016

Member

Needs a t on content

@kaspth

kaspth Feb 25, 2016

Member

Needs a t on content

@@ -0,0 +1 @@
zomg

This comment has been minimized.

@kaspth

kaspth Feb 25, 2016

Member

Don't see this file used for any tests.

@kaspth

kaspth Feb 25, 2016

Member

Don't see this file used for any tests.

chancancode added a commit that referenced this pull request Feb 25, 2016

Merge pull request #23827 from rails/new_implicit_render
Lock down new `ImplicitRender` behavior for 5.0 RC

@chancancode chancancode merged commit 6b31761 into master Feb 25, 2016

0 of 2 checks passed

continuous-integration/travis-ci/pr The Travis CI build is in progress
Details
continuous-integration/travis-ci/push The Travis CI build is in progress
Details

@chancancode chancancode deleted the new_implicit_render branch Feb 25, 2016

@chancancode

This comment has been minimized.

Show comment
Hide comment
@chancancode

chancancode Feb 25, 2016

Member

Merging to unblock the release! We have some ideas for improvements (shortening the error messages and move the details into the HTML page like routing errors, bring back the "searched in..." info, add an config to turn off the "interactive request warning", fine-tune the browser-detection, perhaps express defualt_render in terms of respond_to, etc), but the basic behavior is better than what we have on master. Feel free to open PRs to improve this further

Member

chancancode commented Feb 25, 2016

Merging to unblock the release! We have some ideas for improvements (shortening the error messages and move the details into the HTML page like routing errors, bring back the "searched in..." info, add an config to turn off the "interactive request warning", fine-tune the browser-detection, perhaps express defualt_render in terms of respond_to, etc), but the basic behavior is better than what we have on master. Feel free to open PRs to improve this further

@chancancode

This comment has been minimized.

Show comment
Hide comment
@chancancode

chancancode Feb 25, 2016

Member

Thanks everyone for the hard work!!!

Member

chancancode commented Feb 25, 2016

Thanks everyone for the hard work!!!

@kaspth

This comment has been minimized.

Show comment
Hide comment
@kaspth

kaspth Feb 25, 2016

Member

❤️

Member

kaspth commented Feb 25, 2016

❤️

@maclover7

This comment has been minimized.

Show comment
Hide comment
@maclover7

maclover7 Feb 25, 2016

Member

🎉

Member

maclover7 commented Feb 25, 2016

🎉

@claudiob

This comment has been minimized.

Show comment
Hide comment
@claudiob

claudiob Feb 25, 2016

Member

Should I try adding some new lines to the error message in the following page?

screen shot 2016-02-25 at 8 04 38 am

Member

claudiob commented Feb 25, 2016

Should I try adding some new lines to the error message in the following page?

screen shot 2016-02-25 at 8 04 38 am

@claudiob

This comment has been minimized.

Show comment
Hide comment
@claudiob

claudiob Feb 25, 2016

Member

On a separate note… I think this message is very explicit regarding the edge cases, but it does not convey exactly what to do in the case that will occur 99% of the times.

The old message used to clearly state:

  1. you are missing a file
  2. the file should have one of these names and be in one of these folders

I think we can try to improve the current message and make it more accessible to newcomers, also given that this is part of the Rails guides:

template_is_missing_articles_new

The final part of this message tells us where Rails has looked for the templates. Templates within a basic Rails application like this are kept in a single location, but in more complex applications it could be many different paths.

The simplest template that would work in this case would be one located at app/views/articles/new.html.erb. The extension of this file name is important: the first extension is the format of the template, and the second extension is the handler that will be used. Rails is attempting to find a template called articles/new within app/views for the application. The format for this template can only be html and the handler must be one of erb, builder or coffee. Because you want to create a new HTML form, you will be using the ERB language which is designed to embed Ruby in HTML.

Therefore the file should be called articles/new.html.erb and needs to be located inside the app/views directory of the application.

Member

claudiob commented Feb 25, 2016

On a separate note… I think this message is very explicit regarding the edge cases, but it does not convey exactly what to do in the case that will occur 99% of the times.

The old message used to clearly state:

  1. you are missing a file
  2. the file should have one of these names and be in one of these folders

I think we can try to improve the current message and make it more accessible to newcomers, also given that this is part of the Rails guides:

template_is_missing_articles_new

The final part of this message tells us where Rails has looked for the templates. Templates within a basic Rails application like this are kept in a single location, but in more complex applications it could be many different paths.

The simplest template that would work in this case would be one located at app/views/articles/new.html.erb. The extension of this file name is important: the first extension is the format of the template, and the second extension is the handler that will be used. Rails is attempting to find a template called articles/new within app/views for the application. The format for this template can only be html and the handler must be one of erb, builder or coffee. Because you want to create a new HTML form, you will be using the ERB language which is designed to embed Ruby in HTML.

Therefore the file should be called articles/new.html.erb and needs to be located inside the app/views directory of the application.

@kaspth

This comment has been minimized.

Show comment
Hide comment
@kaspth

kaspth Feb 25, 2016

Member

@claudiob it's been rephrased because you aren't necessarily missing a file. If you expect a 204, then you don't need to do anything.

Member

kaspth commented Feb 25, 2016

@claudiob it's been rephrased because you aren't necessarily missing a file. If you expect a 204, then you don't need to do anything.

@claudiob

This comment has been minimized.

Show comment
Hide comment
@claudiob

claudiob Feb 25, 2016

Member

@kaspth I understand and I agree with this PR, don't get me wrong.

I just think that if you do miss a file (probably still the most common case), we are not telling you anymore where to put that file and which filenames are accepted.

Member

claudiob commented Feb 25, 2016

@kaspth I understand and I agree with this PR, don't get me wrong.

I just think that if you do miss a file (probably still the most common case), we are not telling you anymore where to put that file and which filenames are accepted.

@kaspth

This comment has been minimized.

Show comment
Hide comment
@kaspth

kaspth Feb 25, 2016

Member

Yeah, agreed. And it's one @chancancode's suggestions in #23827 (comment).

Member

kaspth commented Feb 25, 2016

Yeah, agreed. And it's one @chancancode's suggestions in #23827 (comment).

@chancancode

This comment has been minimized.

Show comment
Hide comment
@chancancode

chancancode Feb 25, 2016

Member

@claudiob please continue to improve it!

The case to keep in mind is that..

  1. def update; end is now a sanctioned/idiomatic way to write head :no_content
  2. If you are planning on relying on that behavior, everything might be fine until you decided to debug something in the browser – you might be thinking "this endpoint was working fine since always, was it the gem I just installed? should I restart the server??? what's happening????"

So I think somehow conveying the fact that "this might be okay, actually" is important. But I like @matthewd's suggestion of putting less in the exception message (and probably bring back the info we had before) and put more in the specialized HTML error page.

By the way, since the browser detection might not be perfect (an API explore extension in chrome or a BrokenKit.framework on iOS might send some browser-like headers), it is probably good to have a way to turn it off and mention that on the error page too. ("If you are expected the 204, everything is cool, don't worry. You can also turn this off via... if you like.")

Member

chancancode commented Feb 25, 2016

@claudiob please continue to improve it!

The case to keep in mind is that..

  1. def update; end is now a sanctioned/idiomatic way to write head :no_content
  2. If you are planning on relying on that behavior, everything might be fine until you decided to debug something in the browser – you might be thinking "this endpoint was working fine since always, was it the gem I just installed? should I restart the server??? what's happening????"

So I think somehow conveying the fact that "this might be okay, actually" is important. But I like @matthewd's suggestion of putting less in the exception message (and probably bring back the info we had before) and put more in the specialized HTML error page.

By the way, since the browser detection might not be perfect (an API explore extension in chrome or a BrokenKit.framework on iOS might send some browser-like headers), it is probably good to have a way to turn it off and mention that on the error page too. ("If you are expected the 204, everything is cool, don't worry. You can also turn this off via... if you like.")

@clarkware

This comment has been minimized.

Show comment
Hide comment
@clarkware

clarkware Feb 25, 2016

Thanks to @chancancode for all the work on this!

FWIW, I strongly agree with @claudiob that the message would be improved by addressing the most common case of missing the file. The current message puts a lot of emphasis on the least common case. In fact, given the interactive_browser_request? conditional, I'm not clear on why you'd ever get this message when building an API endpoint as the message suggests. Perhaps I'm missing some nuances.

clarkware commented Feb 25, 2016

Thanks to @chancancode for all the work on this!

FWIW, I strongly agree with @claudiob that the message would be improved by addressing the most common case of missing the file. The current message puts a lot of emphasis on the least common case. In fact, given the interactive_browser_request? conditional, I'm not clear on why you'd ever get this message when building an API endpoint as the message suggests. Perhaps I'm missing some nuances.

@jeremy

This comment has been minimized.

Show comment
Hide comment
@jeremy

jeremy Mar 3, 2016

Member

Noticing that this generally applies to GET requests from the browser.

We have some internal API controllers that take multipart/form-data params or raw request bodies and don't return a response body. To use implicit responses, we'd need to force a fake request.format since it'd fall back to the HTML default, otherwise, and we'd get a missing template error.

Think we can get the best of both worlds by pruning the "is a developer viewing this in the browser and expecting a response?" check down to non-XHR HTML GETs. Non-XHR PUT/POST/DELETE are typically redirects to an HTML GET.

Member

jeremy commented Mar 3, 2016

Noticing that this generally applies to GET requests from the browser.

We have some internal API controllers that take multipart/form-data params or raw request bodies and don't return a response body. To use implicit responses, we'd need to force a fake request.format since it'd fall back to the HTML default, otherwise, and we'd get a missing template error.

Think we can get the best of both worlds by pruning the "is a developer viewing this in the browser and expecting a response?" check down to non-XHR HTML GETs. Non-XHR PUT/POST/DELETE are typically redirects to an HTML GET.

@matthewd

This comment has been minimized.

Show comment
Hide comment
@matthewd

matthewd Mar 3, 2016

Member

@jeremy I worry that'll mean "I forgot to do the redirect" becomes "my browser is pretending I'm not pressing the button" 😕

What Accept is being sent in that situation? No header whatsoever? It definitely seems safe to narrow "browser" down to an explicit request for at least one of text/html or */*.

If we really wanted to get creative, presence of cookies might be worth considering.

Member

matthewd commented Mar 3, 2016

@jeremy I worry that'll mean "I forgot to do the redirect" becomes "my browser is pretending I'm not pressing the button" 😕

What Accept is being sent in that situation? No header whatsoever? It definitely seems safe to narrow "browser" down to an explicit request for at least one of text/html or */*.

If we really wanted to get creative, presence of cookies might be worth considering.

@jeremy

This comment has been minimized.

Show comment
Hide comment
@jeremy

jeremy Mar 3, 2016

Member

Agree. I wager that forgetting a redirect is fairly uncommon and, hopefully, easier to diagnose. The form will submit and you'll get a white page of death in response.

Checking for user-agent details gets tricky since more sophisticated API clients may appear browser-like in all those respects. Then a request could spookily seem to work with some clients but not others.

Member

jeremy commented Mar 3, 2016

Agree. I wager that forgetting a redirect is fairly uncommon and, hopefully, easier to diagnose. The form will submit and you'll get a white page of death in response.

Checking for user-agent details gets tricky since more sophisticated API clients may appear browser-like in all those respects. Then a request could spookily seem to work with some clients but not others.

jeremy added a commit to jeremy/rails that referenced this pull request Mar 3, 2016

Refinement of our "are you missing a template or did you omit it on p…
…urpose?" heuristics

Narrows the "are you in a browser, viewing the page?" check to exclude
non-GET requests. Allows content-less APIs to use implicit responses
without having to set a fake request format.

This will need further attention. If you forget to redirect from a POST
to a GET, you'll get a 204 No Content response that browsers will
typically treat as… do nothing. It'll seem like the form just didn't
work and knowing where to start debugging is non-obvious.

On the flip side, redirecting from POST and others is the default, done
everywhere, so it's less likely to be removed or otherwise missed.

Alternatives are to do more explicit browser sniffing.

Ref #23827.

y-yagi added a commit to y-yagi/rambulance that referenced this pull request Jun 9, 2016

fix broken build
In Rails 5 has changed the behavior of the render, to modify the expected value
in accordance with new behavior.
Ref: rails/rails#23827

y-yagi added a commit to y-yagi/rambulance that referenced this pull request Jun 9, 2016

fix broken build
In Rails 5 has changed the behavior of the render, to modify the expected value
in accordance with new behavior.
Ref: rails/rails#23827

y-yagi added a commit to y-yagi/rambulance that referenced this pull request Jun 9, 2016

fix broken build
In Rails 5 has changed the behavior of the render, to modify the expected value
in accordance with new behavior.
Ref: rails/rails#23827

y-yagi added a commit to y-yagi/rambulance that referenced this pull request Jun 9, 2016

fix broken build
In Rails 5 has changed the behavior of the render, to modify the expected value
in accordance with new behavior.
Ref: rails/rails#23827

@vlymar vlymar referenced this pull request Sep 13, 2016

Closed

Rails5 Support #51

3 of 3 tasks complete

@bf4 bf4 referenced this pull request Oct 24, 2017

Open

Add httpstatus 415, unsupported media type #26632

4 of 4 tasks complete
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment