user4584963
user4584963

Reputation: 2523

How to conditionally add class to <body> in rails layout

My application.html.erb file looks like this

<!DOCTYPE html>
<html lang="en">
  <head>
  .
  .
  .
  </head>
  <body <%= "class=landing-bg" if [email protected]? %>>
    <%= render 'layouts/header' %>
    <div class="container">
    .
    .
    .
    </div>
    <%= render 'layouts/footer' %>
    <% if [email protected]? %>
      <div class="landing-gradient"></div>
    <% end %>
  </body>
</html>

I've left out a bunch of meta tags in the <head> and a bunch of other code in the body that's unrelated to the question.

static_pages_controller

def home
  @landing = "landing"
end

I need to add a class to <body> and a div below the footer only on my home page. I feel like what I am doing is a bit hacky. And, if I created a separate layout just for the landing page it wouldn't be DRY since I would be repeating alot of code that's on this layout.

What is the best way to do this? What is the rails way?

Upvotes: 3

Views: 3114

Answers (3)

Jason Swett
Jason Swett

Reputation: 45074

In my case I want to have a different class per layout (at least potentially), so in app/views/layouts/application.html.erb I do this:

<body class="<%= yield(:body_class) %>">

and then in my layout file I do this:

<% content_for(:body_class) { 'my-class' } %>

Upvotes: 3

Gavin Miller
Gavin Miller

Reputation: 43815

My typical pattern is to add the controller and action into the class of the body, and then use those as selectors in my css like this:

<body class="<%= controller_name %> <%= action_name %>">
  <!-- etc -->
</body>

As for your second issue of a conditionally body on only the home page, you can simply add that into the body in the main layout and display it only on the landing page:

<body class="<%= controller_name %> <%= action_name %>">
  <!-- etc -->
  <div class="landing-gradient"></div>
</body>

# application.css
.landing-gradient {
  display: none;               // Hide the gradient
}

.landing .landing-gradient {
   display: inline;            // Show gradient b/c of more specific selector
}

This is my personal preference since you're leaving display of individual elements to the css / presentation layer instead of within your controllers.

Finally, you could also use a content_for around the footer so that you can customize the footer across individual pages. That's a bit heavy handed for your example though, so I'd only use that if you were customizing the footer a lot.

Upvotes: 7

Sebasti&#225;n Palma
Sebasti&#225;n Palma

Reputation: 33420

You can also manage it without creating an instance variable and verifying it in your view but using the params[:action] and params[:controller]:

<body class="<% 'class_value' if params[:controller] == 'static_pages' && params[:action] == 'home' %>"

You can just validate for the action (method) if you don't have more than one home method.

Upvotes: 1

Related Questions