Rails Cached partial in layout is rendered twice - ruby-on-rails

I am trying to cache a partial which is rendered in a layout. This partial is computationally expensive so I only want to compute it once. It is not controller specific so the usual fragment caching doesn't seem to apply. I decided to use Rails.cache.fetch('menu') for the caching instead. Here is what the contents of the partial look like.
<% Rails.cache.fetch('menu') do %>
Partial code...
<% end %>
But when I do this it renders the partial twice. For some reason it stopped doing this in my development environment so I decided to try and deploy it. I am not so lucky with my production environment. The partial itself generates a menu that includes links to a lot of the records in the site to help improve navigation.
I originally tried putting the cache statement in the layout file but then it was rendering the layout twice.
I recently added a jQuery hack to remove the duplicate html so that it kinda "works" for now, but I would rather get it working properly. I don't want to go to the trouble of installing some complicated caching system such as Redis, that requires me to run another server program. That would be overkill for the task. There must be something in rails that is well suited to caching parts of layouts.
Should I try something completely different or is this a bug in rails? If it is a bug then is there a workaround I can use?

I figured it out. Instead of caching the partial in the view, I created a helper method that returns the rendered partial.
#Returns a menu for the application layout
def menu
Rails.cache.fetch('menu') { render :partial => 'all/menu' }
end
Then all I needed in the layout is this line
<% menu %>

Try clearing your production cache. Chances are you had a logic error that was causing it to render twice. In development, the cache is usually disabled so that's why when you fixed the problem it went away in development. If you have redeployed, the issue is probably gone from the production code as well, but if the cache has not been cleared, it will keep displaying the cached logic error.

Related

In Ruby on Rails is there a way to put the path of every partial in an HTML comment?

I work on apps that often have thousands of partials and finding what partial is rendering a section of HTML can be tedious and just waste time.
In development mode, it would sometimes be very helpful to turn on a config to have every partial used be prefaced with its path in an HTML comment so I could quickly know how to access and edit it.
Is there a config option for this or a gem that someone has made for this?
This functionality is built-in to recent rails versions for erb templates.
See here for details: https://blog.saeloun.com/2020/05/11/rails-support-annotates-html-output-with-template-file-names.html
That page mentions another option you could try.
Here is a link to the rails pr that introduced the change: https://github.com/rails/rails/pull/38848

url_for and controller.controller_name not working on Heroku

I was using controller.controller_name and url_for to highlight various items in a menu bar in my rails app. This worked locally, but once I pushed to Heroku, I was finding that the same menu item was always being highlighted no matter what page I was on, and it was because url_for and controller.controller_name never change even when I go to other views. Why might this be happening. Could this be related to turbolinks? I'm confused because I thought turbolinks was only related to my front end...?
I just ran into this issue and found out it was due to caching the rendered menu.

What is the best practice for Ruby on Rails 3 layout?

Rails 3 offer application.html.erb as a layout template. However, whenever you send request to access a controller view, the content of application.html.erb will be loaded again. This seems not efficient, since header, navigation, footer only need to be loaded once.
In addition, when you need to have a javascript code executed in $(window).load for application.html.erb and another js method executed in $(window).load for <controller>.html.erb, this will mess up. I think the reason is that $(window).load can only execute once for each page.
So I wonder what's the best Layout practice for Rails 3.
Thanks
Rails 4 includes Turbolinks, which will only reload the body of your website when a link is clicked, instead of reloading all of the assets like javascript and CSS. If you want to fine tune what gets loaded further, you can take a look at pjax, but I think for most applications Turbolinks will be sufficient.

using layouts in Rails assets

I have a lot of html pages on my site that are static, but I serve them dynamically through the typical rails controller & view setup just because I want to use my application.html.erb layout and not have to worry about changing it in multiple places if I just cut and paste it into a static html file I put in my public directory.
I recently upgraded to Rails 3.2 however, and the asset pipeline and its precompiling of assets sounded like a perfect fit for this problem. However, I have not seen any good documentation on how to write a *.html.erb asset, and direct it to use application.html.erb, or any other layout for that matter. can someone post how to do this, or point me to a good resource? Thanks!
Instead of trying to serve the static html partials through the asset pipeline, have you thought about just caching them?
If what your worried about is actually getting the static partial to be rendered then you might want to try the following in your view. The following would be for your nav.
-cache 'main-nav' do
=render :partial => 'layouts/nav'
This way on the first load it would retrieve your partial, and all subsequent loads it would retrieve it from your cache, which if you have redis or memcache set up, should make it blazing fast.

Rendering an externally modified file in Rails

I've got a cron job parsing a few XML feeds every ten minutes and creating a few partials to include on every page in my Rails project with the render: file method. The problem is that, obviously, they don't refresh until the server restarts.
Anyway, what can I do to force rails to refresh this file every time?
Thanks in advance.
Use instead:
render :inline => File.read(file_name), :layout => true
I think you are misusing render(:file). This is definitely not how it is intended to be used. Rendering a partial is supposed to be used to render a modular piece of erb (or whatever template lang you use) code in multiple places, not a data-load technique. You're using it (it appears) to load dynamically changing data.
I think what you're really trying to do is fragment caching, but without more context, I could be wrong.
For a great walkthrough on fragment caching: http://www.railsenvy.com/2007/3/20/ruby-on-rails-caching-tutorial-part-2
Probably your cron job would run a script/runner script that would create the fragment you're looking to cache.
If I'm off base here, please try to clarify what type of file you're loading and what you're trying to accomplish.
This happens because in production mode Rails cashes all its classes and views/partials. To solve this problem you can render your partials inside fragment caching block and use method expire_fragment when you want to refresh block content. Other way can be switching to the development mode but it will make your application slower.

Resources