Rails: Assets properly fingerprinted but not stylesheets and javascripts - ruby-on-rails

So this is strange.. On my site, the image assets are getting properly fingerprinted but not the stylesheets and javascript files.
Here's what the link looks like in my view:
<%= stylesheet_link_tag "website", media: "all",
"data-turbolinks-track" => true %>
<%= javascript_include_tag "website",
"data-turbolinks-track" => true %>
And this is what it looks like once pushed to production:
<link data-turbolinks-track="true" href="/stylesheets/website.css"
media="all" rel="stylesheet" />
<script data-turbolinks-track="true"
src="/javascripts/website.js"></script>
.. while my images are properly fingerprinted:
<img src="assets/website/white-logo-904f6978b5ecfdad3fdb8ad8d3a995b6.png">
Any ideas as to why I'm getting this strange behavior, and how I can get it fixed?
Rails v4.0.4 / Ruby 2.1.2

By convention, the Rails asset pipeline recognizes application.js and application.css as the main asset manifest files.
If you want to include separate files, then you'll need to specify them to be precompiled in the environment config or in an initializer.
Try this:
# config/production.rb
config.assets.precompile += %w( website.js website.css )

Related

Capybara RSpec with CSS and JS?

rails (5.1.4)
rspec-rails (3.7.2)
capybara (2.16.1)
I'm trying to create a RSpec Rails 3.7 System spec as in https://relishapp.com/rspec/rspec-rails/v/3-7/docs/system-specs/system-spec .
Here my simple spec:
require 'rails_helper'
RSpec.describe "testing system", type: :system do
it "tests the spec" do
visit root_path
click_link 'Home'
save_and_open_page
end
The problem is that Capybara does render neither CSS content nor JS content after save_and_open_page call (in the browser) - just a plain HTML. The header inside this HTML-file contains some links
<link rel="stylesheet" media="all" href="/assets/application-ea5a1efcc44a908543519edabe00e74132151ebedeef3c1601921690d9162b5e.css" data-turbolinks-track="reload" />
<script src="/assets/application-ff63e43aef379fef744a00f21a8aadf96dc2ae8e612f8e7974b231f946569691.js" data-turbolinks-track="reload"></script>
but they reference some empty files.
Is there some way to fix it?
I tried some recipes, but still no luck. I tried to precompile the assets, to move "capybara.html" into the "public" folder, but no effect.
Modifying stylesheet_link_tag is not a good solution, a much better solution is to specify Capybara.asset_host which will add a <base> tag to any saved pages. Generally this would be set to something like
Capybara.asset_host = "http://localhost:3000/"
which would then load the JS/CSS assets from your dev server which would have access to the test mode compiled assets in the public subdirectory. Note: that none of this means the page will actually be functional since JS requests will still fail, DB records won't exist anymore, etc. Also, since it saves element attributes (not properties) a checkbox you just checked will probably not be checked in the saved page. However it will give you a generally styled page you can inspect the structure of. If all you're looking for is a current image of the page you should be using the save_screenshot/save_and_open_screenshot functionality provided by most of Capybaras drivers instead.
It has to do something with your assets.
Clear cache and run rake assets:clobber and rake assets:precompile
Still no luck, then check if Capybara is configured correctly.
Check app/views/layouts/application.html.erb has the correct Rails tags for stylesheets and javascripts. Something like this:
<!DOCTYPE html>
<html>
<head>
<title>My App</title>
<%= stylesheet_link_tag 'application', media: 'all' %>
<%= javascript_include_tag 'application' %>
On the command line, run:
rake assets:clobber
rake assets:precompile
Ensure that public/assets/ include:
.sprockets-manifest-<xyz>.json
application-<abc>.js
application-<def>.css
Open the .sprockets-manifest... file and you should see that there are application js and css files with filenames that match the actual public/assets/ files. This .sprockets-manifest file controls what actually gets included in the HTML head links and scripts when the Rails tags are replaced.
If this is still not working, ensure that the files are accessible by your user running the test (including the manifest). Occasionally lose the .sprockets-manifest file when copying files and in source control as it can appear to be hidden.
Finally, check your file log/test.log to see if there are any obvious errors being thrown during the tests.
I found a solution. Perhaps it's not the best one, but it works with me. If anybody find a better approach - let me know, please.
Run rake assets:precompile. I didn't even set RAILS_ENV=test.
Modify the stylesheet_link_tag method:
def stylesheet_link_tag2(*sources)
options = sources.extract_options!.stringify_keys
path_options = options.extract!('protocol').symbolize_keys
sources.uniq.map { |source|
tag_options = {
"rel" => "stylesheet",
"media" => "screen",
"href" => path_to_stylesheet(source, path_options)[1..-1]
}.merge!(options)
tag(:link, tag_options)
}.join("\n").html_safe
end
The idea is to turn the rendered link from this:
<link rel="stylesheet" media="all" href="/assets/application-ea5a1efcc44a908543519edabe00e74132151ebedeef3c1601921690d9162b5e.css" data-turbolinks-track="reload" />
to this:
<link rel="stylesheet" media="all" href="assets/application-ea5a1efcc44a908543519edabe00e74132151ebedeef3c1601921690d9162b5e.css" data-turbolinks-track="reload" />
eliminating the leading slash in the href attribute value (since we don't have a server running but just a saved HTML-page).
Replace the code inside the header in \app\views\layouts\application.html.erb to:
<% if Rails.env.test? %>
<%= stylesheet_link_tag2 'application', media: 'all', 'data-turbolinks-track': 'reload' %>
<% else %>
<%= stylesheet_link_tag 'application', media: 'all', 'data-turbolinks-track': 'reload' %>
<% end %>
Write a spec like this:
require 'rails_helper'
RSpec.describe "testing system", type: :system do
it "tests..." do
visit root_path
click_link 'Home'
save_and_open_page Rails.root.join( 'public', 'capybara.html' )
end
end
Add to .gitignore:
/public/capybara.html
Do the same thing with the JS-content.
UPDATE:
If you don't like modifying \app\views\layouts\application.html.erb you can do some monkey patching:
include ActionView::Helpers::AssetTagHelper
alias_method :old_stylesheet_link_tag, :stylesheet_link_tag
def stylesheet_link_tag2(*sources)
options = sources.extract_options!.stringify_keys
path_options = options.extract!('protocol').symbolize_keys
sources.uniq.map { |source|
tag_options = {
"rel" => "stylesheet",
"media" => "screen",
"href" => path_to_stylesheet(source, path_options)[1..-1]
}.merge!(options)
tag(:link, tag_options)
}.join("\n").html_safe
end
def stylesheet_link_tag(*sources)
if Rails.env.test?
stylesheet_link_tag2(*sources)
else
old_stylesheet_link_tag(*sources)
end
end
I usually put such code into app\helpers\application_helper.rb and add include ApplicationHelper into app\controllers\application_controller.rb
UPDATE 2
Setting Capybara.asset_host = "http://localhost:3000/" as #Thomas Walpole advised doesn't work. That's right - how can it work if http://localhost:3000/ is unavailable (AFTER the spec ran)? Of course - when I call save_and_open_page the HTML-file opens with a file://.... address - with no HTTP-server serving it. The attempts to set
Capybara.asset_host = "file://#{Rails.root}/public"
failed - looks like the base HTML-tag supports only http-adresses - not file://... ones. I checked it in Chrome and Firefox.
So my next code proposal is such:
include ActionView::Helpers::AssetTagHelper
alias_method :old_stylesheet_link_tag, :stylesheet_link_tag
def stylesheet_link_tag2(*sources)
options = sources.extract_options!.stringify_keys
path_options = options.extract!('protocol').symbolize_keys
sources.uniq.map { |source|
tag_options = {
"rel" => "stylesheet",
"media" => "screen",
"href" => "file://#{Rails.root}/public" + path_to_stylesheet(source, path_options)
}.merge!(options)
tag(:link, tag_options)
}.join("\n").html_safe
end
def stylesheet_link_tag(*sources)
if Rails.env.test?
stylesheet_link_tag2(*sources)
else
old_stylesheet_link_tag(*sources)
end
end
This eliminates the need to call
save_and_open_page Rails.root.join( 'public', 'capybara.html' )
instead you can simply call
save_and_open_page

Trouble customizing Zurb Foundation with Rails

I am definitely a novice when it comes to SCSS. I need some help.
I am using the Zurb Foundation gem with my Rails 4.2.4 project. I am trying to make some global customizations such as changing the body-bg color. I've gone into the foundation_and_overrides.scss in my assets/stylesheets folder and uncommented
$body-bg: $white;
looking to change it to $steel or some such. When I reload the page, I get
app/views/layouts/application.html.erb where line #7 raised:
Undefined variable: "$white".
application.html.erb starts out:
<!DOCTYPE html>
<html>
<head>
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title><%= content_for?(:title) ? yield(:title) : "foodian" %></title>
<meta name="description" content="<%= content_for?(:description) ? yield(:description) : "Foodian" %>">
<%= stylesheet_link_tag "application" %>
<%= stylesheet_link_tag 'application', media: 'all', 'data-turbolinks-track' => true %>
<%# Modernizr is required for Zurb Foundation %>
<%= javascript_include_tag 'vendor/modernizr' %>
<%= javascript_include_tag 'application', 'data-turbolinks-track' => true %>
<%= csrf_meta_tags %>
I'm sure there is something simple I am overlooking. But I can't find any "for dummies" examples of what to do. Please help.
application.css.scss
/*
* This is a manifest file that'll be compiled into application.css, which will include all the files
* listed below.
*
* Any CSS and SCSS file within this directory, lib/assets/stylesheets, vendor/assets/stylesheets,
* or vendor/assets/stylesheets of plugins, if any, can be referenced here using a relative path.
*
* You're free to add application-wide styles to this file and they'll appear at the bottom of the
* compiled file so the styles you add here take precedence over styles defined in any styles
* defined in the other CSS/SCSS files in this directory. It is generally better to create a new
* file per style scope.
*
*= require_tree .
*= require_self
*/
/*= require foundation */
#import "foundation_and_overrides";
The way I had this working is to add the following line to app/assets/stylesheets/application.scss, and to add this line:
#import "foundation_and_overrides";
You can also remove any *= require foundation from the same file, as foundation_and_overrides already imports the required files.
I am not sure it is the best way, but it works with Foundation 5 (I have not tried Foundation 6 yet).

Rails Fails To Generate Correct Link Path In Production Mode

The app whose in production mode is failed to generate correct links.
For instance, the code below
<%= stylesheet_link_tag 'application', media: 'all', 'data-turbolinks-track' => true %>
<%= javascript_include_tag 'application', 'data-turbolinks-track' => true %>
is generating the code below:
<link rel="stylesheet" media="all" href="/stylesheets/application.css" data-turbolinks-track="true" />
<script src="/javascripts/application.js" data-turbolinks-track="true"></script>
I precompiled javascript and stylesheet. Their correct path is respectively /public/assets/application-0d1386df5e82480bb54a6cd082e626ed2d46d364e867ca7d9ce009d3af8c1718.js and /public/assets/application-5d8165dcf2b8902df77aed37c7ab6fee8c7d62844cb48ece6360d1fa4f079804.css.
Also, I did change config.assets.compile = true in /config/environments/production.rb. But nothing is changed.
If you want to run production mode in your local environment you should tell rails to serve assets itself by changing following
config.serve_static_files = true
In production environment itself you have to configure it using nginx - http://vladigleba.com/blog/2014/03/27/deploying-rails-apps-part-4-configuring-nginx/
and make sure you have reverse your earlier change before pushing it to production.
config.serve_static_files = false

Using asset pipeline outside of ERB

Is there a way to use the rails asset pipeline outside of erg? When I call stylesheet_link_tag(), I get a normal /stylesheets/ link instead of an /assets/ like I'd expect. I suspect that the stache gem just needs to register something with the asset pipeline, but I'm not sure what.
I'm using this gem: https://github.com/agoragames/stache
The code I'm using:
module Layouts
class Application < ::Stache::View
include ActionView::Helpers::AssetTagHelper::StylesheetTagHelpers
def title
'foobar'
end
def stylesheets
[
[stylesheet_link_tag('reset', :media => 'all')]
]
end
def javascripts
end
end
end
It's generating:
<link href="/stylesheets/reset.css" media="all" rel="stylesheet" type="text/css" />
It should be generating (it does this in erb templates):
<link href="/assets/reset.css?body=1" media="all" rel="stylesheet" type="text/css" />
Using rails 3.2.3.
Try
def stylesheets
[
[stylesheet_link_tag("#{ActionController::Base.helpers.asset_path('reset.css')}", :media => 'all')]
]
end
also read https://stackoverflow.com/a/9341764/643500
The proper solution is to remove the:
include ActionView::Helpers::AssetTagHelper::StylesheetTagHelpers
line at the top.

How to have absolute path for stylesheets in mailer with the asset pipeline?

The view helpers in my Mailer template give me relative URLs to the stylesheet and images. Of course, this won't work if I'm viewing the email in Gmail, for example.
In apps/views/layouts/mailer.html.erb
<%= stylesheet_link_tag "application" %>
...
<%= link_to(image_tag("logo.png"), "http://mysite.com") %>
Renders as:
<link href="/assets/application-c90478153616a4165babd8cc6f4a28de.css" media="screen" rel="stylesheet" type="text/css" />
...
<img alt="Logo" src="/assets/logo-d3adbf8d0a7f7b6473e2130838635fed.png" />
How do I get Rails to give me absolute links instead? I'm on Rails 3.1, the asset pipeline is in effect.
`config.action_controller.asset_host handles the host prefix in views generated from an ActionController.
For anything generated in an email you're looking for the ActionMailer configuration options, more specifically:
ActionMailer::Base.asset_host will handle your image_tags and
ActionMailer::Base.default_url_options[:host] will look after your link_to tags.
eg:
ActionMailer::Base.asset_host = "http://blah.com"
ActionMailer::Base.default_url_options[:host] = "blah.com"
Note that you don't need to specify the http prefix for the default url host, you will for the asset host.
I have specified these inside my environment.rb after the application initializer. I would recommend setting an application configuration variable for each environments domain.
For rails 3.2 and ActionMailer use:
config.action_mailer.asset_host = "http://www.example.com"
This might be a bit of a hack, but if you specify an asset host, all helpers will take it into account when rendering links. So if you set
config.action_controller.asset_host = "http://mysite.com"
in your config, stylesheet_link_tag will include the host name.
In this thread rocketscientist and Joe asked about other ideas:
http://apidock.com/rails/ActionView/Helpers/AssetTagHelper/stylesheet_link_tag
You can generate full css as follows (if you do not care about asset hosting). However answer by David Radcliffe should work.
stylesheet_link_tag "http://www.railsapplication.com/style.css" # =>
<link href="http://www.railsapplication.com/style.css" media="screen" rel="stylesheet" type="text/css" />

Resources