Rendering an externally modified file in Rails - ruby-on-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.

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

On demand asset compile Rails

I've some html5/ js game widgets that are shared between my webapp and my ipad app. I've used some ERB code here. The process is, whenever the user purchases a game from ipad, I copy all these assets to a temp folder, zip it and send it back.
Now the problem is, since I'm using ERB, the code is not compiled. This game widget folder is not a part of the asset pipeline as it is required only in certain cases.
Is there a way I can compile these games on demand before copying?
From what I can understand, I'd say your problem lies with your use of ERB code
ERB, like HTML, can only be rendered by a specific technology stack (in our case Rails). This means you need all the other dependencies to make it work, which is where you're hitting problems
Rails
I would recommend your best bet is to create a Rails process to "compile" the JS for you
As a matter of speculation, I'd recommend you'll have to look at creating either a queued job or a scheduled rake task to do this:
Create a special controller action
Use the controller action to load required data
Use a way to create a ZIP file
Save the file
If you'd like me to write some code (although I've never done it for this before), I'll have a look at it for you

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.

Rails Cached partial in layout is rendered twice

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.

Static asset caching on Heroku with Jammit by changing ActionController::Base#page_cache_directory

I'm attempting to use Jammit for packaging CSS and JS for a Rails app deployed on Heroku, which doesn't work out of the box due to Heroku's read only file system. Every example I've seen of how to do this recommends building all the packaged asset files in advance. Because of Heroku's Git-based deployment, this means you need to make a separate commit to your repository every time these files change, which is not an acceptable solution to me. Instead, I want to change the path that Jammit uses to write the cached packages to #{Rails.root}/tmp/assets (by changing ActionController::Base#page_cache_directory), which is writable on Heroku.
What I don't understand is how the cached files will be used without hitting the Rails stack every time, even using the default path for cached packages. Let me explain what I mean:
When you include a package using Jammit's helper, it looks something like this:
<%= include_javascripts :application %>
which generates this script tag:
<script src="/assets/application.js" type="text/javascript"></script>
When the browser requests this URL, what actually happens is that it gets routed to Jammit::Controller#package, which renders the contents of the package to the browser and then writes a cached copy to #{page_cache_directory}/assets/application.js. The idea is that this cached file is built on the first request, and subsequent requests should serve the cached file directly without hitting the Rails stack. I looked through the Jammit code and I don't see how this is supposed to happen. What prevents subsequent requests to /assets/application.js from simply routing to Jammit::Controller again and never using the cached file?
My guess is that there's a Rack middleware somewhere I'm not seeing that serves the file if it exists and forwards the request on to the controller if it doesn't. If that's the case, where is that code? And how would it work when changing ActionController::Base#page_cache_directory (effectively changing where Jammit writes cached packages)? Since #{Rails.root}/tmp is above the public document root, there's no URL that maps to that path.
Great question! I haven't set this up myself, but it's something I've been meaning to look into, so you've prompted me to do so. Here's what I would try (I'll give a shot myself soon, but you are probably going to beat me to it).
config.action_controller.page_cache_directory = "#{Rails.root}/tmp/page_cache"
Now change your config.ru to:
require ::File.expand_path('../config/environment', __FILE__)
run Rack::URLMap.new(
"/" => Your::App.new,
"/assets" => Rack::Directory.new("tmp/page_cache/assets"))
Just make sure not to have anything in public/assets, since that won't ever be picked up.
Notes:
This is for Rails 3. Not sure of the solution under Rails 2.
It looks like Rack::Directory sets cache control headers to 12 hours so Heroku will cache your assets to Varnish. Not sure if Jammit sets this in its controller, but even if it doesn't, it will be cached quite quickly.
Heroku also sets ENV['TMPDIR'] now as well, so you can use that instead of Rails.root + '/tmp' if you wish.
This might be of use, it's for a different gem but the idea is similar and I'm trying to get it working with the plain asset helpers.
http://devcenter.heroku.com/articles/using-compass
Unfortunately it seems to be quite difficult to get rails to do this without patching/rewriting the asset helpers module (which resembles coupled spaghetti).

Resources