I am using the rspec_api_documentation and apitome gems in a version 5.2 ruby on rails app.
This produces excellent documentation, and has a sidebar (div#sidebar) to allow quick access to the correct part of the documentation. When I choose the
config.layout = "layouts/application.html.erb"
option in the apitome.rb initializer, the documentation is rendered, but the sidebar has disappeared. Looking at the page source, the code for the sidebar is not being rendered, i.e. it is not a css problem, the html is not being put into the layout. To make sure it was not something unusual in my application.html.erb file, I simplified it to this
<!DOCTYPE html>
<html>
<head>
</head>
<body>
<%= yield %>
</body>
</html>
This sidebar is very useful, so how do I render it in a layout?
Based on the response to this issue, I was able to solve this.
I created a new layout at app/views/layouts.apidocs.html.erb which rendered apitome/docs/navigation. A simple example would be as follows
# app/views/layouts/apidocs.html.erb
<!DOCTYPE html>
<html>
<head>
</head>
<body>
<div class="container">
<div class="row">
<div class="col-md-4">
<div id="sidebar" class="sidebar hidden-print" role="complementary">
<%= render 'apitome/docs/navigation' %>
</div>
</div>
<div class="col-md-8" role="main">
<div class="docs-section">
<%= yield %>
</div>
</div>
</div>
</div>
</body>
</html>
I then configured this layout in the
apitome initialiser.
# config/initializers/apitome
Apitome.setup do |config|
...
config.layout = "layouts/apidocs.html.erb"
end
After some css tinkering, it all looked good.
Related
I have a structure which looks like below where-in I need to call a .html.erb file in another.
main_layout.html.erb
<html>
<head>
</head>
<body>
<div>
how to call the sub_layout here
</div>
</body>
</html>
sub_layout.html.erb
<div>
<p> This is the nested layout to be rendered inside main_layout </p>
</div>
I tried with the below options.
<%= render sub_layout.html.erb %>
<%= ERB.new(open("sub_layout.html.erb").read).result(binding) %>
Both of the above options is not working. Any suggestions please?
# main_layout.html.erb
<html>
<head>
</head>
<body>
<div>
<%= render 'sub_layout' %>
</div>
</body>
</html>
This will look for a file _sub_layout.html.erb in the same folder as main_layout.html.erb
If the _sub_layout.html.erb is not in the same folder as main_layouts.html.erb you need to define the complete path <%= render 'your/path/to/sub_layout' %>
I think you can rename your file from "sub_layout.html.erb" to "_sub_layout.html.erb" and run it.
My application.html.erb file looks like this
<!DOCTYPE html>
<html lang="en">
<head>
.
.
.
</head>
<body <%= "class=landing-bg" if !#landing.nil? %>>
<%= render 'layouts/header' %>
<div class="container">
.
.
.
</div>
<%= render 'layouts/footer' %>
<% if !#landing.nil? %>
<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?
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.
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' } %>
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.
I have a common layout which, by default, should display a (basic) search form on each page excepted the search page itself which contains a (more advanced) search form already.
Is it possible to pass a parameter from my search page to the layout in order to not display the default search form?
Here is an example of what I would like to do:
layout.html
<html layout:???="displayShowForm = true">
...
<form action="search" th:if="${displayShowForm}">...</form>
...
<div layout:fragment="content">...</div>
home.html (show the default search form)
<html layout:decorator="layout">
...
<div layout:fragment="content">...</div>
search.html (hide the default search form)
<html layout:decorator="layout (displayShowForm = false)">
...
<div layout:fragment="content">
...
<form action="advancedSearch">...</form>
Yes, it's entirely possible, even though Thymeleaf's documentation doesn't clearly state it.
All you have to do is pass your param using the th:with attribute. There may be other methods, but this seems to be the most straight-forward.
Here's a stripped down version of my implementation:
Default decorator - fragments/layout/default.html
<!doctype html>
<html xmlns:layout="http://www.thymeleaf.org" xmlns:th="http://www.thymeleaf.org">
<body>
<div th:replace="fragments/header :: main"></div>
<div layout:fragment="content">
main content goes here
</div>
</body>
</html>
Header fragment - fragments/header.html
<!doctype html>
<html xmlns:th="http://www.thymeleaf.org">
<body>
<div th:fragment="main">
<nav>
<ul>
<li>Home Page</li>
<li>About</li>
</ul>
</nav>
</div>
</body>
Home Page file - home.html
<!doctype html>
<html layout:decorator="layout/default" th:with="currentPage='home'"
xmlns:layout="http://www.thymeleaf.org/" xmlns:th="http://www.thymeleaf.org">
<body>
<div layout:fragment="content">
This is my home page content... thrilling, isn't it?
</div>
</body>
</html>
Here, in the home.html file, you can see I include the default decorator and pass my parameter using the th:with attribute. I don't actually use my parameter in my layout decorator, but I use it in header.html, which is included from the decorator. No need to pass it from the decorator to the header.html fragment, since it's already in scope.
There was also no need to do a NULL check on the currentPage variable in header.html. The active CSS class was simply not appended when removing the parameter from home.html.
If I were to render home.html, I would expect to see the following output:
<!doctype html>
<html>
<body>
<nav>
<ul>
<li>Home Page</li>
<li>About</li>
</ul>
</nav>
<div>
This is my home page content... thrilling, isn't it?
</div>
</body>
</html>
Yes, it is possible to pass parameters but you need to use layout:include instead of layout:decorator or layout:fragment.
Similar to Thymeleaf's th:include, but allows the passing of entire
element fragments to the included page. Useful if you have some HTML
that you want to reuse, but whose contents are too complex to
determine or construct with context variables alone.
Source : https://github.com/ultraq/thymeleaf-layout-dialect
You should take a look at this documentation which will give you details about the way to use it.
In your case, it could look like :
<div layout:include="form" th:with="displayShowForm=true"></div>
And in the layout page of form :
<div layout:fragment="form">
<div th:if="${displayShowForm} == true">
<form action="basicSearch"></form>
</div>
<div th:if="${displayShowForm} == false">
<form action="advancedSearch"></form>
</div>
</div>
Having looked around for hours, reading blogs and many other SO questions with no success, I finally got to ask for help.
I believe I still lack some understanding about the Rails layout/render/yield mechanisms.
Therefore this maybe a stupid question. I beg your pardon.
Is it possible to prevent partials from being rendered on every page request? I mean, every time I click a link on my app the layouts and partials are reloaded.
My goal is to have a somehow static side bar, populate it once by rendering the partial "the first time application.html.erb is loaded", and then update it using ajax only.
Here is my app layout:
<!DOCTYPE html>
<html>
<head>
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title><%= content_for?(:title) ? yield(:title) : "GEN" %></title>
<meta name="description" content="<%= content_for?(:description) ? yield(:description) : "GEN" %>">
<%= stylesheet_link_tag "application", :media => "all" %>
<%= javascript_include_tag "application" %>
<%= csrf_meta_tags %>
</head>
<body class="darkbody">
<header class="navbar navbar-fixed-top navbar-inverse">
<nav class="navbar-inner">
<div class="container-fluid">
<%= render 'layouts/navigation' %>
</div>
</nav>
</header>
<main role="main">
<div class="container-fluid">
<div class="row-fluid">
<div class="span3">
<%= render partial: 'charts/dashboard', layout: false %>
</div>
<div class="span9">
<div class="well well-small">
<%= render 'layouts/messages' %>
<%= yield %>
</div>
</div>
</div>
</div>
</main>
</body>
</html>
The "dashboard" partial should load once and never be rendered again.
In other words, navigating the app would change/refresh content in the yield section but not in the main layout "partials".
The motivation? The dashboard uses a helper method to show a value that is computed and never updated throughout the user session. If I get many reloads this helper runs on every user click and stresses the app server even if returning the same result, what happens indeed.
Is this too crazy or stupid?
Best regards,
AD
Actually, it will render HTML from this template on each request, but if data which is displayed in template doesn't need to be actual all the time, you can try action or fragment caching, like this:
<div class="span3">
<% cache 'dashboard' do %>
<%= render partial: 'charts/dashboard', layout: false %>
<% end %>
</div>
You can read more details in rails guides (http://guides.rubyonrails.org/caching_with_rails.html#fragment-caching)
Short:
Do you put the data-role portions (header|content|footer) in your layout/master page or in each view in ASP.NET MVC?
Long:
Trying to find the 'best practice' with handling jQuery mobile layout. The docs (and some others) show:
<!DOCTYPE html>
<html>
<head>
<title>Page Title</title>
...
</head>
<body>
<div data-role="page">
<div data-role="header">...</div>
<div data-role="content">#RenderBody()</div>
<div data-role="footer">...</div>
</div>
</body>
</html>
However I have seen this too :
<!DOCTYPE html>
<html>
<head>
<title>Page Title</title>
...
</head>
<body>
<div data-role="page">
#RenderBody()
</div>
</body>
</html>
With each view having:
<div data-role="page">
<div data-role="header">...</div>
<div data-role="content">...</div>
<div data-role="footer">...</div>
</div>
So, do you define the header|content|footer in each 'view' in ASP.NET or in the layout/master? Is one better? Does it matter at all?
I've noticed that navigation (using the back button) only works correctly when you use the first option (DRY). I am facing the same issue. If I want different header content how do you change this if you have one layout page. I think the way to go is to create sections in the master layout page and enable them per view as required.
RenderSection("SectionName")
Personally, I've been using the second practice for Don't-Repeat-Yourself sake.