Skip to content

Comments

Layouts and Rendering Guide#5

Open
bhumi1102 wants to merge 24 commits intomainfrom
bhumi-guides-layouts-and-rendering
Open

Layouts and Rendering Guide#5
bhumi1102 wants to merge 24 commits intomainfrom
bhumi-guides-layouts-and-rendering

Conversation

@bhumi1102
Copy link
Owner

@bhumi1102 bhumi1102 commented Mar 20, 2024

  • Some of the content seems to be explaining render (and redirect/head methods) from the controller's perspective, rather than the view, and then the rest of the guide is about structuring layouts, including partials for instance which are also explained in the AV Overview guide.
    -> Removed the partial duplication and restructured quite a bit to separate out the sections
  • The guide starts by implying the reader knows about the Controller, but reading the guides top-to-bottom, views come first (since it's organized in MVC order), so we should at least link to the basic controller guide, and not imply the users knows things. ("as you know")
  • There's a note about using the file extension as determination for the choice of template handler, it's bit of a black box and could be clarified. Maybe there's more about it in the controller guide? Doesn't look like it.
    -> code examples of few options help here
  • Old mention of some option that "was required on Rails 2.2 and earlier", no need for that anymore.
  • send_file should be linked if mentioned.
  • First time we mention variants, very briefly, it may warrant a more detailed section. Also uses a different "home" controller, instead of keeping using the same "books" example. (it's generally nicer/better to stick to the same example if possible, makes it easier to follow)
    -> Updated to books.
  • The example in template inheritance should probably be render(@products) || render("empty_list"), as render returns nil if the collection is empty, so that condition in the example seems wrong.
  • There's a section on partials from the view perspective, but no mention that you can actually render partial: from a controller like the other options.
  • The section "Difference Between render and redirect_to" seems very long for what should be simple to explain, and I also don't think we should be showing the last example that renders the "index" again. You should either 404 or redirect in that example, not render all books from a show action.
  • The javascript_include_tag section might be outdated with the recent updates, it still talks about sprockets serving the JS assets.
  • content_for? is mentioned in the nested layouts section, but could be explained with the main content_for block first.

@bhumi1102 bhumi1102 changed the title intro wording Layouts and Rendering Guide Mar 26, 2024
@bhumi1102
Copy link
Owner Author

Hi @carlosantoniodasilva - I wanted to request your thoughts on the updated structure of Layouts and Rendering guide. It isn't ready for a full line by line review yet (I've make it to line 700 out ~1000) but before I end work for this month I wanted to ask if this looks better than before overall and I'm happy to incorporate any structural feedback early.

Screen Shot 2024-03-28 at 10 32 30 PM Screen Shot 2024-03-28 at 10 33 21 PM

@carlosantoniodasilva
Copy link
Collaborator

@bhumi1102 sorry I didn't get to this one last week... I think the overall structure looks better, yes. The one thing to consider at a glance, is whether "options for render" warrants its own main section vs staying as a subsection.

Other than that, my initial thinking is related to the fact that it still includes content both very related to Action Controller, and Action View, and whether you are thinking about breaking that further somehow? I know they're super tied together, but there's things I'm not sure fit in the same guide... for instance, explaining redirect_to / head versus layouts for partials / nested layouts. Very separate concepts, that are more related to controller or view respectively.

The way I've been sort of thinking about it is that we could have the AV Overview, and an "AV Advanced" (i.e. Layouts and Rendering potentially, but from AV's perspective only) guide, and we'd have the current AC Overview, plus an "AC Advanced / AC Rendering & Responses" of some sort, that'd be tying AC + AV: render, redirect, head, selecting the layout, and so on. That's what I think Layouts and Rendering is trying to do, but mixing with some "AV Advanced" content that's very much AV-specific. Maybe it doesn't make sense, and we just keep Layouts and Rendering as an advanced concept that goes through these topics together, but in my mind it seems that distinction/separation/organization could be beneficial.

/cc @p8 for any input as well.

@bhumi1102
Copy link
Owner Author

Thanks @carlosantoniodasilva, and no worries! I'm only able to work on guides 2 to 3 hours each week for the month of April so I'll be little slow as well. But I'll focus on getting something ready for an internal review is next.

whether "options for render" warrants its own main section vs staying as a subsection.

Agree. I think that can go back to subsection.

The way I've been sort of thinking about it is that we could have the AV Overview, and an "AV Advanced" (i.e. Layouts and Rendering potentially, but from AV's perspective only) guide, and we'd have the current AC Overview, plus an "AC Advanced / AC Rendering & Responses" of some sort, that'd be tying AC + AV: render, redirect, head, selecting the layout, and so on.

I read something along those lines in your original TODO task. What I'll plan to do next is come up the main headers + sub-headers for each of these guides (in my 3 hours next week) and see if we can get somewhere better with separation/organization. It's not immediately clear to me what content will go where, so I'll give it shot and see!

@p8
Copy link
Collaborator

p8 commented Apr 11, 2024

@carlosantoniodasilva @bhumi1102 I've always found the focus of this guide confusing. It also doesn't help that we handle Action View before Action Controller, but still reference controllers in the Action View guides.
I also agree this guide shouldn't handle redirect_to and head.
Looking at the index menu, It seems there is some missing guide when going from "Getting Started" to the more in-depth guides. Maybe we should have a "Model, View and Controller" guide under the getting started guide that has some overlap with this guide?

Looking at the "Getting Started" guide, it first generates a model and then a controller (which will create the views). I think having that order makes sense.
Some suggestions/questions:

  • Maybe we should avoid ordering by the MVC acronym and just do what makes sense for the guides (MCV)?
  • Maybe the "Active Record Basics", "Action View Overview" and "Action Controller Overview" guides should be grouped with the "Getting Started" guides? The current "Model", "View", "Controller" sections would be the advanced sections.
  • Should we split the "Getting Started" guide into separate guides: "Setting Up Rails", "Model, View, Controller". That last one would have some overlap with this guide. Although building your first Rails app conflicts with some in-depth guide.

@p8
Copy link
Collaborator

p8 commented Apr 11, 2024

Also, some of the current guide titles don't describe what they help you do. After "Getting Started" (helping you get started), the next one is "Active Record Basics" (what does this do if I don't know what Active Record is?).
Having something like "Modeling your Domain", "Rendering Responses" or "Building a CRUD application" would be more descriptive.

@carlosantoniodasilva
Copy link
Collaborator

We haven't looked into the "Getting Started" guide because that was going to get a full review/rewrite as part of a tutorial work at some point, so we kinda skipped it.

I do agree it would make sense to explain Controller before View in the order of things, not necessarily following the "MVC" order there.

As for the titles, it could make sense to have them be more descriptive, or at least reworking/improving the description of the guides (which is something worth doing nonetheless I think). Let's maybe move this part of the discussion to Basecamp so others can chime in, @p8 if you want to start a new to-do or discussion there about it.

For this guide in particular, what bothers me a bit is that it's under "View", but it's a mixed guide that's mostly about rendering layouts / views from the "Controller"'s perspective, with some view-specific/only stuff. My thinking was to decouple that some, and make it a more complete / advanced guide on rendering stuff from the "View" perspective, leaving another guide to handle the "Controller->View" portion. I hope that makes sense.

@bhumi1102
Copy link
Owner Author

bhumi1102 commented Apr 26, 2024

Hello! I'm back after longer than expected delay, sorry about that.

So. To attempt to disentangled this "layouts and rendering" guide, I created two new guides. Names are placeholders and open to changing, but here's what I called them so far: 1. Action Controller Response and Rendering 2. Action View Layouts. For 1. I'm envisioning would go in the "Controller" section, and 2. is for the "View" section. Images attached to show what the headers / subheaders look like at a high level.

Basically I'm thinking that all the sections about render/redirect_to have to do with responses from controller action and with controller-->view handoff, like we're been talking about. The sections about finding the right layout to render, content_for, and all that has to do with composing a complete page from view template/partial/layout.

More work is needed on both guides, write an intro and create flow, etc. But wanted to share this first.

Screen Shot 2024-04-26 at 10 55 43 AM Screen Shot 2024-04-26 at 10 39 02 AM

Oh and I hear you Petrik about "Getting Started" and MVC and what goes where. I'll plan to capture that into a separate 'todo' in basecamp.

Copy link
Collaborator

@p8 p8 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This split and rewrite of guides is great @bhumi. It reads a lot better and has a better focus.

end
```

But we do not need write the above boilerplate `index` action. You'd define the `index` method once you need to do anything other than `render :index`. If you create a `Book` model and add the following index action to `BooksController`:
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
But we do not need write the above boilerplate `index` action. You'd define the `index` method once you need to do anything other than `render :index`. If you create a `Book` model and add the following index action to `BooksController`:
But we do not need to write the above boilerplate `index` action. You'd define the `index` method once you need to do anything other than `render :index`. If you create a `Book` model and add the following index action to `BooksController`:

Creating Responses Using `render`
---------------------------------

This section describes the various way in which you can customize the behavior of `render`. The controller's [`render`][controller.render] method does the heavy lifting of constructing a response to HTTP requests and sending your application's content to the client.
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
This section describes the various way in which you can customize the behavior of `render`. The controller's [`render`][controller.render] method does the heavy lifting of constructing a response to HTTP requests and sending your application's content to the client.
This section describes the various ways in which you can customize the behavior of `render`. The controller's [`render`][controller.render] method does the heavy lifting of constructing a response to HTTP requests and sending your application's content to the client.

Comment on lines +113 to +115
* Call [`render`][controller.render] to create a full response to send back to the browser. More examples in [Creating Responses Using `render` section](#creating-responses-using-render).
* Call [`redirect_to`][] to send an HTTP redirect status code to the browser. More examples in [Creating Responses Using `redirect-to` section](#creating-responses-using-redirect-to)
* Call [`head`][] to create an HTTP header only response. More in [this section](#building-header-only-responses-using-head).
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A fourth options is streaming data to the browser:
https://edgeapi.rubyonrails.org/classes/ActionController/DataStreaming.html

Comment on lines +289 to +290
NOTE: Unless overridden, your response returned from this render option will be
`text/plain`, as that is the default content type of Action Dispatch response.
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ignore this if it's too much of a nitpick 😄

If we reference Action Dispatch Response should we capitalize response?

Suggested change
NOTE: Unless overridden, your response returned from this render option will be
`text/plain`, as that is the default content type of Action Dispatch response.
NOTE: Unless overridden, your response returned from this render option will be
`text/plain`, as that is the default content type of Action Dispatch Response.

If instead it references a response should we add "an"?

Suggested change
NOTE: Unless overridden, your response returned from this render option will be
`text/plain`, as that is the default content type of Action Dispatch response.
NOTE: Unless overridden, your response returned from this render option will be
`text/plain`, as that is the default content type of an Action Dispatch response.


With most of the options to `render`, the rendered content is displayed as part of the current layout. This guide covers more about [finding](#) and [using layouts](#) in the sections below.

If you need to use a layout other than the current layout Rails uses by default, you can use the `:layout` option to specify a file to use as the layout for the current action:
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This could sentence is pretty long and a bit hard to parse. Maybe we can split it up a bit?
We also specify a template instead of a file I think.

Maybe:

Suggested change
If you need to use a layout other than the current layout Rails uses by default, you can use the `:layout` option to specify a file to use as the layout for the current action:
If you need to use a layout, other than the current layout Rails uses by default, you can use the `:layout` option to specify a template to use as the layout for the current action:

Or maybe something like:

Suggested change
If you need to use a layout other than the current layout Rails uses by default, you can use the `:layout` option to specify a file to use as the layout for the current action:
If you need to use a layout other than the default layout, you can use the `:layout` option to specify a template to use as the layout for the current action:

redirect_back(fallback_location: root_path)
```

NOTE: `redirect_to` and `redirect_back` do not immediately stop the execution of the controller method, they simply set HTTP responses. So statements *after* `redirect_to` in our controller get executed. To terminate the execution of the method immediately after the `redirect_to`, you need to use `return`. For example `redirect_to book_url(@book) and return`
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
NOTE: `redirect_to` and `redirect_back` do not immediately stop the execution of the controller method, they simply set HTTP responses. So statements *after* `redirect_to` in our controller get executed. To terminate the execution of the method immediately after the `redirect_to`, you need to use `return`. For example `redirect_to book_url(@book) and return`
NOTE: `redirect_to` and `redirect_back_or_to` do not immediately stop the execution of the controller method, they simply set HTTP responses. So statements *after* `redirect_to` in our controller get executed. To terminate the execution of the method immediately after the `redirect_to`, you need to use `return`. For example `redirect_to book_url(@book) and return`


NOTE: `redirect_to` and `redirect_back` do not immediately stop the execution of the controller method, they simply set HTTP responses. So statements *after* `redirect_to` in our controller get executed. To terminate the execution of the method immediately after the `redirect_to`, you need to use `return`. For example `redirect_to book_url(@book) and return`

[`redirect_back`]: https://api.rubyonrails.org/classes/ActionController/Redirecting.html#method-i-redirect_back
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
[`redirect_back`]: https://api.rubyonrails.org/classes/ActionController/Redirecting.html#method-i-redirect_back
[`redirect_back_or_to`]: https://api.rubyonrails.org/classes/ActionController/Redirecting.html#method-i-redirect_back_or_to


The `render` call will find the `index.html.erb` file and attempt to render it. However, the `index` view expects a `@books` instance variable to be set. Since we are coming from the `show` action, while trying to render the `index` view, the `@books` instance variable will *not* be set. Note that `render action: "index"` does *not* execute the code in the `index` controller action before rendering the view, it just attempts to render the view specified.

This is the difference between `render` and `redirect_to`. The `redirect_to` method ends the current action, the browser makes a brand new HTTP request, which in turn, execute the appropriate controller action.
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
This is the difference between `render` and `redirect_to`. The `redirect_to` method ends the current action, the browser makes a brand new HTTP request, which in turn, execute the appropriate controller action.
This is the difference between `render` and `redirect_to`. The `redirect_to` method ends the current action, the browser makes a brand new HTTP request, which in turn, executes the appropriate controller action.


Just like the `:status` option for `render`, `:status` for `redirect_to` accepts both numeric and symbolic values.

The Difference Between `render` and `redirect_to`
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This section seems to describe when to use render and when to use redirect_to.
Maybe the following header would be clearer? This would also mean that line 558 should change.

Suggested change
The Difference Between `render` and `redirect_to`
When to use `render` or `redirect_to`

Or maybe:

Suggested change
The Difference Between `render` and `redirect_to`
Choosing between `render` and `redirect_to`


With this code, the browser will make a new request for the index page, the code in the `index` method will run, which will set the `@books` instance variable, then the `index.html.erb` view will be rendered. And it will all work as expected.

Note that the above example is for demonstration. It is not typical to render all books from a `show` action for a given book. If a resource is not found, it is reasonable to return a HTTP 404 Not Found status code when `@book.nil` is true.
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If the example is not typical, should we use a more typical example like a create action instead?
This example could also explain that a redirect prevents a double submit when using the back button after a form is submitted?

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

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants