How to prevent partials in main layout from being re-rendered/updated on every page request? - ruby-on-rails

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)

Related

How to call a .html.erb file inside another .html.erb file

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.

Apitome sidebar disappears when included in a layout

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.

Capybara ambiguous match - should have_content

I'm using Capybara and Rspec in a Rails app, and I keep failing some of my tests with this message :
Failure/Error: it { should have_content('error') }
Capybara::Ambiguous:
Ambiguous match, found 2 elements matching xpath "/html"
And that's kind of logical, because in my test, my app should render two messages with the 'error' content.
<% if object.errors.any? %>
<div id="error_explanation">
<div class="alert alert-error">
<%= t('the_form_contains') %>
<%= pluralize(object.errors.count, t('error')) %>.
</div>
<ul>
<% object.errors.full_messages.each do |msg| %>
<li>* <%= msg %></li>
<% end %>
</ul>
</div>
<% end %>
And here my application layout :
<!DOCTYPE html>
<html>
<head>
<title><%= full_title(yield(:title)) %></title>
<%= stylesheet_link_tag "application", media: "all", "data-turbolinks-track" => true %>
<%= javascript_include_tag "application", "data-turbolinks-track" => true %>
<%= csrf_meta_tags %>
<%= render 'layouts/shim' %>
</head>
<body>
<%= render 'layouts/header' %>
<div class="container">
<div class="row-fluid">
<div class="offset2 span8 offset2">
<% flash.each do |key,value| %>
<div class="alert alert-<%= key %>"><%= value %></div>
<% end %>
</div>
</div>
<%= yield %>
<%= render 'layouts/footer' %>
<%= debug(params) if Rails.env.development? %>
</div>
</body>
</html>
Do you know a way (like an option), to make it pass ?
EDIT
I used save_and_open_page and I didn't found any additional html tag, neither error messages outside the page. But when I remove <!DOCTYPE html> then it works. Must I really have <!DOCTYPE html> and an opening <html> tag ? Can I delete <!DOCTYPE html> without consequences ?
<!DOCTYPE html>
<html>
<head>
<title>Le Troquet</title>
<link data-turbolinks-track="true" href="/assets/application.css" media="all" rel="stylesheet" />
<script data-turbolinks-track="true" src="/assets/application.js"></script>
<!--[if lt IE 9]>
<script src="http://html5shim.googlecode.com/svn/trunk/html5.js"></script>
<![endif]-->
</head>
<body>
.
.
.
.
.
<!-- There is no html tag here -->
.
.
.
.
</body>
</html>
It looks like the problem is that you either:
have two <html> tags in your page, or possibly
the "error" text appears outside the <html></html> tags.
See this discussion: Ambiguous match, found 2 elements matching xpath "/html".
Check for elements outside of the closing </html> tag. In my case (HAML), I had a javascript tag that was improperly indented
%html
...
:javascript
FIX
%html
...
:javascript
...
Indenting the :javascript so it was contained within the html tag solved the issue.
OK, I understand the problem. When I use should have_content, Capybara search in the whole layout the content. But it finds two html tags, that make it fails, because it doesn't know which is the right one. And why is there two html tags ? Because Capybara doesn't ignore the <!DOCTYPE html>.
I solved my problem, but it's more of a bypass. Instead of searching a content, I made Capybara search for the 'error' div, that contains the 'error' messages. Thereby, it doesn't have to search the whole application layout, and it doesn't get stucked with the two html tags.
So I just had to replace it { should have_content('error') } by it { should have_selector('div', text: 'error') }, and it worked.

gmaps4rails on jQueryMobile map not showing when redirecting

I am using gmap4rails on jQueryMobile but the map is not showing when I'm doing a redirecting to the page showing the map. The map shows normally when I refresh the map page, but not when I redirect to the page showing the page. Does anyone have an idea why? Thanks! Below is the code
/app/views/items/map.html.erb
<div data-role="header">
<h1>Market</h1>
<%= link_to 'Sell/Buy', new_item_path, "data-icon" => "plus", "class" => "ui-btn-right" %>
<%= link_to 'Back', root_path, "class" => "ui-btn-left" %>
</div>
<div class="center-wrapper">
<div data-role="controlgroup" data-type="horizontal">
List
Map
</div>
</div>
<div data-role="content">
<%= gmaps4rails(#json) %>
</div>
/app/views/layouts/application.html.erb
<!DOCTYPE html>
<html>
<head>
<title>Project</title>
<%= stylesheet_link_tag "application", :media => "all" %>
<link rel="stylesheet"
href="http://code.jquery.com/mobile/1.3.1/jquery.mobile-1.3.1.min.css" />
<%= javascript_include_tag "application" %>
<script src="http://code.jquery.com/mobile/1.3.1/jquery.mobile-1.3.1.min.js"></script>
<meta name="viewport" content="initial-scale=1, maximum-scale=1">
<%= csrf_meta_tag %>
</head>
<body>
<div data-role="page">
<%= yield %>
<%= yield :scripts %>
</div>
</body>
</html>
/config/routes.rb
ProjectZ::Application.routes.draw do
...
match '/map', to: 'items#map'
end

Favicon shows up on rails local, not on hosted app

I put my favicon.ico in my public folder, and it shows up on my localhost, but when I check it out on the internet, shows up instead. My app is hosted through heroku, and the domain is provided by hover. Where is this failing?
Also, in case this helps, here is the code I'm using to render the favicon:
<!DOCTYPE html>
<html>
<head>
<link rel="shortcut icon" href="/favicon.ico" />
<title>Shoulak Predictions</title>
<%= stylesheet_link_tag 'application', media: 'all' %>
<%= javascript_include_tag 'application' %>
<%= csrf_meta_tags %>
<%= render 'layouts/shim' %>
</head>
<body>
<%= render 'layouts/header' %>
<div class="container">
<% flash.each do |key, value| %>
<div class="alert alert-<%= key %>"><%= value %></div>
<% end %>
<%= yield %>
</div>
<div class="container">
<%= render 'layouts/footer' %>
<%= debug(params) if Rails.env.development? %>
</div>
</body>
</html>
Update
If I go to mydomain.com/favicon.ico, I do download the favicon that I uploaded. ALSO, if I go to therealapp.herokuapps.com, it shows up. I think somehow my domain provider may be providing their own?
Adding a random number in your favicon will force the update:
<link rel="shortcut icon" href="/favicon.ico?v=2" />
Once I cleared my browser cache, the favicon showed up.
I've found that it takes time for that change to show up. Something to do with browser caches or server settings or something.
I was doing Hover forwarding, not using the DNS features. Hover automatically uses their own favicon.
Please check on another browser, it will work surely. It takes time to reflect.
Below my working code.
<link rel="icon" type="image/png" href="../static/images/icon.png"/>

Resources