Usually the recommended solution is content_for
in the parent layout file. But this results in having to specify it in every view since the default becomes not displaying it if the content is not present in the child view partial.
For example, if I have a sidebar that I want to hide in authentication pages, but have it everywhere else, I now have to specify content of the sidebar in every view file except the authentication pages. Not DRY.
This is much more cumbersome and not dry than before, where I could render a sidebar partial in the layouts and be done with it (but not have the benefit of choosing where it does or doesn't render).
It would be nice if you could somehow specify in the layouts template that calls the sidebar partial to not tender if it's a session controller or devise controller.
Is there any way to do this? I've tried using
unless devise_controller?
render "layouts/sidebar"
But this doesn't seem to work as intended.
Taking an example with Devise, I have an application.html.slim file like so
.row
main
.col-sm-9
= yield
- unless devise_controller?
.col-sm-3
== render 'layouts/sidebar'
Ignore the columns for a moment. The main point is that the =yield
renders normal templates as well as the devise templates. So I can't selectively disable the sidebar in one DRY stroke. I would have to put the sidebar render call in every view file, but not include it in my devise views. That's no better or DRYer than using content_for in every non-devise view file.
And getting back to the columns, I would like to have the yielded devise views full width of 12 columns, not 9 columns. But that's just bonus, not the main question.
I simply implemented the verbose way of doing things. I'll use a complex example since it might be more helpful.
Here, I set up the full cases, depending on whether I want a sidebar or not, mainly because of the way bootstrap columns and rows work. If you're using bootstrap, you'll notice that once you prevent the sidebar from rendering, you'll be left with the rest of the main content not taking the space that the sidebar no longer takes. This is because you previously had to put the sidebar and main content in a specific column width, and those in a row (so that they appear side by side). Since you want the main content to fill and take the full width when the sidebar is gone, you have to apply completely different column widths in that case. Hence the full if - else statement.
Thus, implement it like so, making sure to include .rows
and .col-*-*
in each of your main yielded view files.
application.html
- if hide_sidebar?
main
= yield
- else
.row
.col-xs-12.col-sm-9
main
= yield
.col-xs-12.col-sm-3
== render 'layouts/sidebar'
If the list of pages you wish to have or not have a sidebar becomes more complex than simply all of the actions of a certain controller, implement a separate helper method specifying all the conditions.
This is one way to do it, in the controller. In my example, I want to hide the sidebar when it's the registrations controller and when it's the show action of the users controller. I just ||
each out in the helper method.
application_helper.rb
def want_sidebar?
(controller_name == 'registrations') || ( (controller_name == 'users') && action_name == 'show' )
end