How can I control max-age for particular files with Rails? - ruby-on-rails

I have Rails serving my static assets. Most of them have hashes in their name and are served with far-future expiration dates. But for one file, I can't serve it with a hash in its name, so I need to control the expiration date.
I have this in my application.rb which applies to all static assets:
config.static_cache_control = "public, max-age=2592000"
Is there a way for me to have a different max-age for just one file? I know I can make a new middleware that comes after ActionDispatch::Static and changes the value for certain files (see this writeup)... but then this will run for every single request, even those which aren't static assets. Is there a more elegant solution?

A bad technique can be to fix the URL of your file in your route.rb. You can define a Controller to this route fixing the cache_control you want and use send_data method to server the file.

Related

Rails Sprockets file uses local manifest for digests instead of asset host version

In our web application built in Rails we have several clients using the same application who will have different assets that are used dependant on which subdomain is used.
To achieve this we swap out what folder is being used on the CDN like so:
config.action_controller.asset_host = Proc.new { |source, request|
if request.subdomain.present?
"http#{request.ssl? ? 's' : ''}://cdn.domain.com/#{request.subdomain}/"
else
"http#{request.ssl? ? 's' : ''}://#{request.host_with_port}/"
end
}
Each time we create a new client we compile the assets manually using a custom build tool that uses Sprockets to build the assets the same way Rails would and then upload them to our CDN under a folder that matches the subdomain. This then allows us to have different sets of assets based purely on the subdomain.
Now this works fine except that when we update an asset the digest will change for that file but Rails will still try and load the old asset digests because the sprockets-manifest file (which is in /public/assets) e.g. .sprockets-manifest-12345.json is being loaded instead of the one that's on the CDN. Even though the asset host is different it still loads the local one.
Rails it seems doesn't care about other manifest files as the file itself only stores the filename to the fingerprinted version so even when things like the host changes it would normally be able to find the correct asset. It would seem as though Rails has been designed this way deliberately.
However we really need to get Rails to use the manifest file that is on the CDN itself rather than use the one in the public folder local to the application.
After reading the docs, it seems you can change the manifest location. We tried doing it by using the same logic as above for the manifest like so:
config.assets.manifest = Proc.new { |source, request|
if request.subdomain.present?
"http#{request.ssl? ? 's' : ''}://cdn.domain.com/#{request.subdomain}/"
else
"http#{request.ssl? ? 's' : ''}://#{request.host_with_port}/"
end
}
But Rails/Sprockets is still using the local sprockets file... Any ideas why?

duplicate Rails 4 asset fingerprint file on Heroku

I'm getting duplicate asset fingerprint javascript file on Heroku production.
This initially creates around 3-4 files then after a while (a day), it creates another set of those files again. Also every time I refresh those files get rotated in the source.
On production.rb:
config.assets.enabled = true
config.assets.digest = true
config.action_controller.asset_host = "//#{ENV['FOG_DIRECTORY']}.s3.amazonaws.com"
config.assets.initialize_on_precompile = true
config.assets.precompile += %w( '.woff', '.eot', '.svg', '.ttf', '*.css.scss', application_user.js, popcorn.js )
On application.rb:
config.assets.enabled = true
config.assets.digest = true
Surely this doesn't matter?
Structure
The Rails structure is such that it should allow you to use whatever fingerprinted file you need, and it will show (using the dynamic javascript include helpers)
If you're unable to read a particular file because it's not exactly the same as it was before is, in my opinion, a highlight of a poor system design
Files
I think I remember your issue from another day -- you can just use the helper method to call the files you need. It shouldn't cause any issues with the different names. It's all part of the asset pipeline
I'd recommend looking into how you're calling the files - if you're trying to call the hashed filename directly, you're going to have an issue

Issue with using CDN and https: (Rails)

In my Rails application, i have used CDN. I have configured the cdn by adding cdn url to
config.action_controller.asset_host = "http://cdn.mydomain.com"
in production.rb file.
Now i am trying to have https:// for certain pages like Sign In and Sign Up
But as the assets are served from CDN, the https conflicts with the cdn path.
My solution to this to make the sign in and sign up pages not to use the cdn assets and should point
as local assets.
is my solution correct? if so how do i restrict certain layout files from using CDN asset path?
I would look at this response: Configure dynamic assets_host in Rails 3
What I think you would want to do is change asset_host to be dynamic based on whether your page is served over https or not. Something like:
config.action_controller.asset_host = Proc.new { |source, request|
"#{request.ssl? ? '/assets' : 'http://cdn.mydomain.com'}"
}
My syntax may be a little off as I'm typing it up on the fly but it should be close to what you need.
NOTE : The code request.try(:ssl?) always returns false even when i run the https version.
I am working on finding the solution, will post it once i find it.
Found the solution
config.action_controller.asset_host = Proc.new do |*args|
source, request = args
if request.try(:ssl?)
'https://mydomain.com'
else
'http://cdn.mydomain.com'
end
end

Set url to be used for assets

I have a rails app
salmonfishing.com
which has a database. I have another app
salmonfishing-test.com
How can I alias the root url so that when a user goes to
http://salmonfishing-test.com
the assets and data from the
http://salmonfishing.com database
will be used.
My database.yml points to the 'salmonfishing' database, but the generated url for an image is
http://salmonfishing-test/bigfish.png
That is as would be expected, however internally I would like that to be aliased to
http://salmonfishing.com/bigfish.png
...basically so all assets and data are served from 'salmonfishing' database, and saved to it. Ran across various ways of setting sub-paths, but not root for assets and data.
Cheers,
Jet
If your only problem is the wrong domain name in your asset URLs, you can change it in your environment config file: config/environments/[whatever].rb:
config.action_controller.asset_host = "http://salmonfishing.com"
This line is already present in production.rb, but it's commented out.

Switch asset host for controller

Trying to figure out a way to change up the asset host when accessed by a certain controller.
The controller is to be strictly accessed by the https protocol, so I need the asset host to be switched over to using https. At the moment the asset host is set to a CNAME subdomain that is linked to the S3 and there is no SSL cert associated to it. What I'm trying to achieve is replace the current asset host with the https Amazon S3 URL. The only assets I'm worried about are the CSS and JS includes.
I was thinking of using a helper to strip the host from the stylesheet_link_tag and javascript_include_tag and replace them with the https Amazon S3 url. Seems a bit hackish to me though.
Or perhaps there is a way to changed asset hosts if request.ssl? is true?
I'm using Rails 3.2.x.
Figure out a solution for my case.
Ended up using a Proc on config.action_controller.action_host in my Production environment file to handle a logic on request.ssl? and respond accordingly. Here is the code
config.action_controller.asset_host = Proc.new { |source, request = nil, *_|
request && request.ssl? ? 'https://s3.amazonaws.com/my_bucket' : 'http://s3.my-domain.com'
}
'request' is set to nil to accomodate the cases where asset_host is called in asset files (CSS and JS if you are using the asset helper tags). Since request doesn't exist and if request isn't assigned in the args, then the error will be thrown when assets are compiled (as shown below).
This asset host cannot be computed without a request in scope. Remove the second argument to your asset_host Proc if you do not need the request, or make it optional.
The *_ is present due to a bug with option arguments in Proc http://bugs.ruby-lang.org/issues/5694

Resources