AWS to serve CSS images Sinatra - ruby

I am using the asset_sync gem to sync my assets to a S3 bucket. In production i want to use S3 and in development i want to use my local files. So i have setup the following along with a helper
environments/development.rb
configure :development do
set :asset_host, "/"
end
environments/production.rb
configure :production do
set :asset_host, "https://s3-eu-west-1.amazonaws.com/#{ENV['FOG_DIRECTORY']}"
end
helper
helpers do
def aws_asset( path )
File.join settings.asset_host, path
end
end
So in my views i can do this
<%= image_tag( aws_asset "/assets/images/wd.png") %>
Which will result in rendering that image from my local assets if in development or from my bucket when in production
So what if i want to render an image from within my main.css file, such as a background image? I cant do the below for example as its not an erb file
main.css
header{
background: #ffffff url('<%= aws_asset("/assets/images/bgwRpeat.png") %>') repeat-x;
}
So what can I do? Has anyone done this before
Thanks for any help anyone can offer

3 ways come to mind.
Precompile the assets
Before you deploy, precompile the assets and CSS. If you create a file called main.css.erb and then run it through ERB to produce main.css it'll have the right stuff inside. This would be my preference. There are lots of ways to precompile, I prefer Guard but YMMV.
Edit:
Lifted and twisted from the Guard::Erb docs
guard 'erb', :input => 'app/views/stylesheets/main.css.erb', :output => "public/assets/stylesheets/main.css" do
watch (%r{app/views/stylesheets/main.css.erb})
end
Something like that.
Create a route that then compiles the assets
This is similar to how you might use SASS templates with Sinatra (if you don't precompile them). Just do the same as above, set up a route for main.css, run the main.css.erb template through ERB and serve it. Add lots of caching.
Edit:
get "/assets/stylesheets/main.css" do
# remember to look at caching
erb :"stylesheets/main.css"
end
I started writing and I can't remember the 3rd :) In my defence, I've a terrible headache. Perhaps someone else will remember for me.

Related

serving static files on sinatra

I'm working on a Sinatra app for the first time and am stumbling into an issue with serving a javascript asset.
I am following the Sinatra convention of putting the static files in “public” folder and it works locally but when we create a Docker image, we get a 404 while this works with localhost.
I see where I can set the public_folder which I have tried like this:
http://sinatrarb.com/configuration.html
but still 404'ing. Is there a way to get the top-level object and ask it where it expects the public_folder to be (like Rails.env)?
You can check the settings object.
irb(main):001:0> require "sinatra"
=> true
irb(main):002:0> settings.public_folder
=> "/usr/lib/ruby/2.5.0/irb/public"
This allows you to create a route which returns the path, something like this
require 'sinatra'
get '/' do
settings.public_folder
end
Without more information I would guess that your public folder points to a wrong directory inside your docker because the project :root points to a different directory that what you expect.

Why won't Rails find my assets?

When in production mode, rails can't seem to find any precompiled assets from the asset pipeline.
I'm using rails 3.2.0 and ruby 1.9.3 running inside RVM on CentOS. No additional web server is running in conjunction with this application. The application was only recently updated to use the asset pipeline, as it was originally a rails 3.0 app.
After running
rake assets:clean
rake assets:precompile
I see the hashed content in public/assets, as I would expect. The hashes at the end of the files match those I see in the page source.
Yet at runtime, here's what I see for every asset Rails tries to serve:
Started GET "/assets/application-892c6227e631daf9a8e041b1d4d002ec.css" for 75.149.58.169 at 2012-03-14 11:42:43 -0700
ActionController::RoutingError (No route matches [GET] "/assets/application-892c6227e631daf9a8e041b1d4d002ec.css"):
I'm not referring to the folder that each asset is housed in; all references to assets look like these:
//css:
.class {
background: url(asset.png) no-repeat;
}
//erb:
<%= image_tag "asset.png" %>
<%= link_to "page", :class => "class" %>
Asset pipeline pertinent settings in production.rb:
config.serve_static_assets = false
config.assets.enabled = true
config.assets.compress = true
config.assets.debug = false
config.assets.compile = false
config.assets.digest = true
And lastly, asset settings from config/application.rb:
config.assets.enabled = true
config.assets.version = '1.0'
The user starting the rails server process has read, write and execute permissions on public/assets, so I don't think it's a permissions issue. Have I missed a configuration step?
Edit
I noticed that there are no errors stating that assets are not precompiled, so I tried to access a stylesheet from the web page by appending"/assets/application-892c6227e631daf9a8e041b1d4d002ec.css" to the end of the host path:
http://www.myapp.com"/assets/application-892c6227e631daf9a8e041b1d4d002ec.css"
This worked and the stylesheet opened.
Further researching of this issue yielded this SO article:
application.css not being served as an asset
It seems
config.serve_static_assets = false
Is an incorrect setting as long as my Rails application is not running behind Apache or nginx
I had this same problem, but I note that your stylesheet is pointing to the non-fingerprinted, non-cached version of the files. If you are using the asset pipeline, in order to take advantage of it, you need to use the helpers that point to the fingerprinted, cached version of the files. To do this, you'll need to either embed erb in your css file, or use sass.
Incorrect:
.class {
background: url(asset.png) no-repeat;
}
Correct (uses sass):
.class
background: image-url('asset.png') no-repeat
For more info, see here: http://guides.rubyonrails.org/asset_pipeline.html#coding-links-to-assets
If you don't care about the performance issues, you can get away with using the non-cached versions until you upgrade to Rails 4 or Rails 3.2.16, because those versions introduce breaking changes that force you to use the asset pipeline (and its corresponding syntax). If you don't use the new syntax, the non-cached versions will not work at all on production.

Rails 3.1, exclude JS files from asset pipeline

I know there are a million questions already on this, but I can't get this.
I want to include most of my JS files in the asset pipeline, but I have a few I want to load conditionally (or only on certain pages). These are big, complicated files and will never, ever be used by 95% of the users, so I'd rather not have them loaded for every user. One set of JS files is for a calendar, placed in:
app/assets/javascripts/calendar
So my manifest is set up to include only the top directory (and exclude the calendar subdirectory):
//= require jquery
//= require jquery_ujs
//= require jquery-ui
//= require_directory .
My config/environments/production.rb:
# Compress JavaScripts and CSS
config.assets.compress = true
# Don't fallback to assets pipeline if a precompiled asset is missed
config.assets.compile = false
# Generate digests for assets URLs.
config.assets.digest = true
# This following config is left over from previous Rails app,
# so not sure if it's now unnecessary ...
# Disable Rails's static asset server
# In production, Apache or nginx will already do this
config.serve_static_assets = false
In the view, I'm using Ryan Bates' nifty_layout to manually include the calendar files:
javascript "calendar/date.js", "calendar/jquery.weekcalendar.js", "calendar/custom.js"
I've tried precompiling in both development and production -- the docs aren't clear where I'm supposed to do this, but it looks like production.
And when I run the page, I get this:
ActionView::Template::Error (calendar/date.js isn't precompiled)
I don't want it precompiled. I want it loaded manually. (Actually, it would be OK to precompile in a file other than the main application.js that is created, but I don't know how to do that.)
What's the solution?
Thanks!
OK, I didn't realize this was how it works, but I think I figured it out.
Add the files to be manually loaded to config/environments/production.rb like so:
config.assets.precompile += %w( calendar/*.js jquery_calendar/*.css )
I thought this just folded them into the application.js and application.css, but apparently not -- it compiles them as individual files.
Then, you can call the files as you traditionally would (in this case, using nifty_layout):
javascript "calendar/date.js", "calendar/jquery.weekcalendar.js", "calendar/custom.js"

How to set HTTP response (cache) headers in a Sinatra app hosted on Heroku

I have a fairly simple app (just one index.html file and a css file - it really is just a static page) hosted on Heroku.
I use Sinatra to host it on Heroku. The 'app' itself is fairly simple:
require 'rubygems'
require 'sinatra'
get "/" do
File.read(File.join('public', 'index.html'))
end
The question is, how do I set the HTTP response header for the static assets? In particular, I wanted to set the Expires header for caching purposes.
EDIT: I'm looking to add the said header to the static assets (ie, the one that resides under /public, like background images, icons, etc)
Apart from the fact that I wouldn't get through the Sinatra stack just to serve static files, you'd call
cache_control :public, max_age: 60
to cache for a minute. cache_control is a helper that comes with Sinatra.
Otherwise, I'd suggest you have a look at http://www.sinatrarb.com/configuration.html to see how Sinatra is set up so you don't have do deal with serving static files.
Hope this helps.
edit: I just saw you were explicitly asking for the Expires header. I'm not sure, but that should be fairly the same way as Cache-Control. Sorry for the confusion
As an expansion to #awendt's answer, Sinatra can actually handle static files with out needing to explicitly define the route and print the file.
By adding:
set :static, true
..you can add your index.html and stylesheet.css to a public/ folder. Then when you visit http://localhost:9292/stylesheet.css you'll be provided with the static file.
If you want to use another folder name, instead of the default public/, then try:
set :public, "your_folder_name"
If we want to be less explicit we can just create the public/ folder in the knowledge that Sinatra will enable :static for us anyway :)
Source: http://www.sinatrarb.com/configuration.html#__enabledisable_static_file_routes

Generate URL for file in /public in Rails 2 ERB view

In my rails (v2.3.8) app I have a static resource file which I've put at /public/myfile.kml No need for any special routes.rb setting right?
It serves up just fine at http://localhost:3000/myfile.kml
When I deploy (to passenger) it appears at http://myserver/myappname/myfile.kml
All is well so far...
I have a view (an erb file) which spews out javascript which needs to reference this file. The output needs to be '/myfile.kml' on localhost, and '/myappname/myfile.kml' in production, or maybe the full URLs as above, or maybe a relative url involving a bit of '../../../' (awkward with RESTful URLs).
Should I be able to do something like <%=url_for 'myfile.kml'%> ?
or '<%=ROOT_URL%>/myfile.kml'
I know there's an insanely easy answer to this question, but honestly I've had no luck finding it. Quite a few people talking about 'root_url' but what is that? A variable I can reference in a view? It's undefined.
I'm not sure about Rails 2.3.8, but in Rails 3 this value defaults to false.
edit config/environments/production.rb and set:
config.serve_static_assets = true
Also, here's a blog post that shows a helper for linking to a static resource (favicon)
http://ilconnettivo.wordpress.com/2008/07/28/favicon-on-rails/
'<%= ENV["RAILS_RELATIVE_URL_ROOT"] %>/myfile.kml'
<%= RAILS_ROOT + "/public/myfile.kml" %>
Inspection of rake routes reveals the helper root_path for use in views. For example <%= root_path + 'myfile.kml' %> By default will map to files under public/ in a rails application.
The latest (>2.3.6) is Rails.root, see:
http://joneslee85.wordpress.com/2010/05/27/the-dilemma-of-rails-root-vs-rails_root-complex/
Why not just replicate your production environment locally? A webserver is not very resource hungry and it can help resolve some ecosystem configuration issues like you're seeing here.

Resources