Static pages and assets in Rails 3.1.1 - ruby-on-rails-3

Currently working on a project where we need to drop in various static html pages + static assets for those from time to time that "just work." We cannot have anyone editing the html directly to place paths in for the assets. We need it to simply work such that the html + asset folders are placed directly into /public and the content is served up as it was generated.
When testing this behavior in production, it's a no go with errors such as:
ActionController::RoutingError (No route matches [GET] "/some_folder/some-image.png"):
I assume this is a result from what I'm reading from 3.1.x's asset pipeline.
How do you alter the routes such that these will be served up directly? Or is there a preferred way to keep this precise behavior? (Ultimately this will be deployed on heroku.)
Adding some more details as current remarks have not yet pushed my issue over the edge in terms of a solution:
In my present scenario I'm running it straight on WEBrick rails s -e production to test it out. In development mode this does work properly; the only exception is in production.
I am also running this prior to running the server:
bundle exec rake RAILS_ENV=production RAILS_GROUPS=assets assets:precompile --trace
When I actually attempt to load the page in production, I see the following output:
cache: [GET /] miss
cache: [GET /test_files/index.css] miss
cache: [GET /test_files/index.js] miss
cache: [GET /test_files/logo.png] miss
cache: [GET /test_files/background.png] miss
cache: [GET /test_files/horizontal.png] miss
cache: [GET /favicon.ico] miss

Upon further scrutiny of the production.rb I am seeing: "config.serve_static_assets = true" that when set to false by default evokes the issue experienced in webrick. So when setting that to true it serves the files up properly.
From some additional reading it appears that perhaps Heroku needs this set to false as well, which is the environment to which we're deploying.
Thanks for the input, but this appears to be the approach to take for now and I'd certainly appreciate any further input if this is NOT the correct answer or if there's a better approach.

As of Rails 3.1.1 the precompile task creates non-digested as well as digested filenames, so you can refer to these in static files (while still having the digest version in dynamic files).
The only problem is if you use far-future headers on the assets directory; changes to the undigested files won't be pick up by remote clients that still have a copy and believe the cache to still be valid.
You may need to look at an approach the replaces the non-digested filenames with the correct name during the deployment process.
If you do not use far-future headers in the directory then it does not matter - you can use either name.

For me the #ylluminate's answer helped: I've changed the config.serve_static_assets option to true in the config/environments/production.rb file and restarted the server with
$rails server --environment=production
and now it serves compressed assets.
NOTE: I've also precompiled the assets with
$bundle exec rake assets:precompile
(call rake this way assure will be used the rake version choosen for the project but I guess use just rake assets:precompile will work 99% of the times)

If you have /public/some_folder/some-image.png physically present (no matter if you just copied it there manually or it was generated by assets precompile), it must work. The server (e.g. Apache) will first check if the requested path exists in public, if it does it won't even call Ruby on Rails.
As far as digested filenames are concerned there is an option to turn this feature off, but I wouldn't recommend that for reasons already mentioned by someone else here.
Also you can put files that refer to assets in the app/assets folder and add a .erb extension AT THE END. Then you can use <%= asset_path ... %> inside that file, so no manual editing will be necessary. This will work even if you already have some other preprocessing on the file, for example sass - style.css.scss.erb will work. First the erb code will be evaluated (putting in the correct filenames for assets) then the sass compiler will be ran.

Oh and have a look at the sprockets-image-compressor gem, just add it to your Gemfile and it will automagically compress image assets too (losslessly using pngcrush and jpegoptim)...I don't know if the gem is rock-solid but from what I've seen I love it!

Related

Rails 3 Development Asset Pipeline Directs to Public Folder

I just pulled down two new rails 3.2.6 projects that I have designated for some clean up. While attempting to make some UI changes I realized that even in development the asset pipeline was routing towards the public/assets folder.
After making some changes to the scss, I ran rake assets:clean followed by rake assets:precompile. Both ran without error and I restarted my localhost, and the styling was broken.
I've walked through the rails asset pipeline guide, as well as some other documentation that hasn't really provided the answer I need.
I attempted adding config.serve_static_assets = falseto the development.rb file in the config folder, however this as well did not render any scss.
Can anyone explain what is happening, and the best method of resolution?
Thanks
Add below statement to development.rb to prevent loading of files from public/assets.
config.serve_static_assets = false
Now restart the server, You will get better view.
To precomple the code in Test mode. -
Add this configuration to test.rb
config.assets.compile = false
config.serve_static_assets = true

How to get the error log from SASS when using the rails asset pipeline?

I've got 3 Rails 3.2 applications using the gem jquery-ui-themes. jquery-ui-themes uses scss for the image-path helper.
It works great on two of my applications, but the 3rd doesn't seem to compile the scss files in either development or production modes.
IOW, it sends this to the browser
background: #fcfdfd url(image-path("jquery-ui/redmond/ui-bg_inset-hard_100_fcfdfd_1x100.png")) 50% bottom repeat-x;
whereas the two working apps properly send
background: #fcfdfd url("/assets/jquery-ui/redmond/ui-bg_inset-hard_100_fcfdfd_1x100.png") 50% bottom repeat-x;
I've spent many hours trying to make the app that's broken as similar to possible to the two working apps as I can, but it's still failing.
My theory is that SASS is choking on something previous to redmond.css.scss. If so, there should be an error logged somewhere. Where do I find the error output from SASS?
Update:
I introduced a deliberate error into redmond.css.scss and I got a proper error dump. So I know that I'm correctly clearing the cache and actually running sass. Now to figure out why it's ignoring the image-path directives.
If you're looking for the answer to the question in the title, the answer is "the same way you get any other errors: they're in your log". To get a full backtrace, just point your browser at the asset: ie http://localhost:3000/assets/jquery-ui/redmond.css in my case.
Make sure you clear all your caches: rm -rf .sass-cache/ && rm -rf public/assets && rake tmp:cache:clear, as well as using ctrl-shift-r in your browser.
If you're looking for the answer for my real problem (image-path not working), make sure you have the proper Bundler.require line in your application.rb. The old Rails 3.0 doesn't work.
replace:
# If you have a Gemfile, require the gems listed there, including any gems
# you've limited to :test, :development, or :production.
Bundler.require(:default, Rails.env) if defined?(Bundler)
with:
if defined?(Bundler)
# If you precompile assets before deploying to production, use this line
Bundler.require(*Rails.groups(:assets => %w(development test)))
# If you want your assets lazily compiled in production, use this line
# Bundler.require(:default, :assets, Rails.env)
end

Make asset pipeline act like production on development

I am experiencing some problems with assets on production: missing ones, stuff compiled into the wrong files (javascript for "/admin" getting compiled into the frontend code and so on). Most of the assets come from engines. I want to debug and optimize this.
For that, I need to precompile, serve and fail on my development environment just like it is done on production.
I have added some lines to my config/development.rb:
config.serve_static_assets = true
config.assets.precompile += %w( store/all.js store/all.css admin/all.js admin/all.css ) # #TODO: clean up, and optimize.
config.assets.compile = false
Running this with rake RAILS_GROUPS=assets RAILS_ENV=development assets:precompile gives me all the assets and the manifest.yml in public/.
But then the server fails:
Sprockets::Helpers::RailsHelper::AssetPaths::AssetNotPrecompiledError in Spree/home#index
Showing /xxxx/app/views/spree/shared/_head.html.erb where line #13 raised:
favicon.ico isn't precompiled
favicon.ico isn't precompiled. But it is! Its there, in the public dir, in manifest.yml, and I can fetch it with the browser (or wget): http://localhost:3000/assets/favicon.ico.
NOTE Favicon is simply the first asset called. If I strip out favicon, the problem simply surfaces with the next asset, being "all.js", or, when that is stripped, "all.css", and so on. I can strip it untill "footer_bg.png", and it will then fail there. Again: the problem is not favicon, but the fact that the development environment does not see the precompiled assets at all.
What more is needed to get development asset pipeline similar to production?
EDIT: More explicit explanation that favicon is not the problem, merely a symptom.
I ended up installing an apache, passenger on localhost to troubleshoot.
Apache (could probably be any passenger-able server) because of the static asset serving.
Furthermore, on localhost I can bump the verbosity of apache in its logs very high, offering me enough debug information.
Passenger to emulate the ruby version and the gem-loading as much as possible as on production.
Running on webrick is just too different, even when emulating as close as possible, it proved too different from a production stack; which is why I could not reproduce the production problems in there,
Firing up the whole stack as if it were production allowed me to troubleshoot. Which lead me to conclude that several problems were causing the asset-woes: a gems assets not being picked up; a permission issue (compiled assets not readable by www-data) and a few assets not being compiled properly.
I think you may want to leave favicon.ico in public...
alzabo0:~ $ rails --version
Rails 3.2.3
alzabo0:~ $ rails new ojoijoijo
[...]
create public/404.html
create public/422.html
create public/500.html
create public/favicon.ico
create public/index.html
create public/robots.txt
[...]
Just a guess, but try adding to your precompile list:
config.assets.precompile += %w( store/all.js store/all.css admin/all.js admin/all.css favicon.ico)

How can I run SOME initializers when doing a Rails assets:precompile?

Background
I have an app that I recently updated to Rails 3.2.1 (from Rails 3.0.x) and have refactored the JS and CSS assets to make use of the new asset pipeline. The app is hosted on Heroku with the Celadon Cedar stack.
App Config
I keep application specific configuration in a YAML file called app_config.yml and load it into a global APP_CONFIG variable using an initializer:
# config/initializers/load_app_config.rb
app_config_contents = YAML.load_file("#{Rails.root.to_s}/config/app_config.yml")
app_config_contents["default"] ||= {}
APP_CONFIG = app_config_contents["default"].merge(
app_config_contents[Rails.env] || {} ).symbolize_keys
Asset Compilation on Heroku
Heroku has support for the Rails asset pipeline built into the Cedar stack. When you push an app to Heroku it automatically calls rake assets:precompile on the server as a step in the deploy process. However it does this in a sandboxed environment without database access or normal ENV vars.
If the application is allowed to initialize normally during asset precompilation an error is thrown trying to connect to the database. This is easily solved by adding the following to the application.rb file:
# Do not load entire app when precompiling assets
config.assets.initialize_on_precompile = false
My Problem
When initialize_on_precompile = false is set, none of the initializers in config/initializers/* are run. The problem I am running into is that I need the APP_CONFIG variable to be available during asset precompilation.
How can I get load_app_config.rb to be loaded during asset compilation without initializing the entire app? Can I do something with the group parameter passed to Rails::Application.initialize! ?
Rails lets you register initializers only in certain groups, but you need to use the Railtie API:
# in config/application.rb
module AssetsInitializers
class Railtie < Rails::Railtie
initializer "assets_initializers.initialize_rails",
:group => :assets do |app|
require "#{Rails.root}/config/initializers/load_config.rb"
end
end
end
You don't need to check if AppConfig is defined since this will only run in the assets group.
And you can (and should) continue to use initialize_on_precompile = false. The load_config.rb initializer will be run when initializing the app (since it's in config/initializers) and when pre-compiling without initializing (because of the above code).
Definitely check out asset_sync on github. Or our Heroku dev centre article on Using a CDN asset Host with Rails 3.1 on Heroku.
The issues with environment variables have recently been solved by a Heroku labs plugin, that makes your application's heroku config variables accessible during compilation time. To enable this, read about the user_env_compile plugin.
Also. There is quite a big performance improvement in using asset_sync vs letting your application lazily compile assets in production or serving them precompiled directly off your app servers. However I would say that. I wrote it.
With asset_sync and S3 you can precompile assets meaning all the assets are there ready to be served on the asset host / CDN immediately
You can only require the :assets bundle in application.rb on precompile, saving memory in production
Your app servers are NEVER hit for asset requests. You can spend expensive compute time on, you know. Computing.
Best practice HTTP cache headers are all set by default
You can enable automatic gzip compression with one extra config
Here's what I came up with. In the assets that need app configuration, I place this line at the very beginning:
<% require "#{Rails.root}/config/initializers/load_config.rb" unless defined?(AppConfig) %>
... and add .erb to the file name, so that video_player.js.coffee becomes video_player.js.coffee.erb. Then I can safely use AppConfig['somekey'] afterwards.
During the asset pre-compilation, it loads app config despite the initialize_on_precompile set to false, and does it only once (which avoids constant redefinition issues).
Yes, it's a kludge, but many times nicer than embedding configs in asset files.
For Heroku I am running the Asset Sync gem to store my files on a CDN to avoid hitting Heroku for static images. It works nicely. I also have initialize on precompile false, but the Asset Sync runs it's own initializer so you could put your code in that. https://github.com/rumblelabs/asset_sync
Although your intializer is not run when the assets are precompiling, you should still find that they run as Rails boors up as normal, however, this will be on the first hit to the application rather than at the deploy step.
I'm not entirely sure what the issue you're having is, but if you follow the Rails conventions the deploy will work as expected.

Multiple public folders, single rails installation

I have a rails application I would like to use for multiple sites, each with different designs.
I would like to change the rails installation /public directory to something else (dynamically eventually). However, I have run into a problem (bug?) changing directories...
In my application.rb file I change the paths.public path to something other than "public" (let's say "site_one"). Here is the code:
puts paths.public.paths
paths.public = "site_one"
puts paths.public.paths
The two "puts" commands are for debugging. Now run "rails s" and you will see:
/home/macklin/app/public
/home/macklin/app/site_one
This verifies the path is changed correctly. However, shortly afterward, rails throws the following error (let me know if you need the full trace):
Exiting
/usr/lib/ruby/gems/1.8/gems/railties-3.0.3/lib/rails/paths.rb:16:in `method_missing': undefined method `javascripts' for #<Rails::Paths::Path:0x7f422bd76f58> (NoMethodError) from /usr/lib/ruby/gems/1.8/gems/actionpack-3.0.3/lib/action_controller/railtie.rb:47
My guess is it cannot find the javascripts directory even though it is clearly sitting in the "site_one" folder.
Does anyone know why I am getting this?
I know this question is pretty old, but I think I found an answer for this in Rails 4.2.
You just simply have to put this line in your config/application.rb:
middleware.use ::ActionDispatch::Static, "#{Rails.root}/another_public_folder_name", index: 'index', headers: config.static_cache_control
This makes all files in /another_public_folder_name to be served by Rails.
This is the way Rails use to setup the standard /public folder. I found it checking the sources:
https://github.com/rails/rails/blob/52ce6ece8c8f74064bb64e0a0b1ddd83092718e1/railties/lib/rails/application/default_middleware_stack.rb#L24
Duh. Just add 2 more rules for stylesheets and javascripts (I guess they get wiped when you change the parent path)
paths.public.stylesheets = "site_one/stylesheets"
paths.public.javascripts = "site_one/javascripts"