I want to use application.css on my email templates, but I can't find a way to make the stylesheet_link_tag helper to include the full url of the stylesheet so email clients can render properly.
By default, stylesheet_link_tag only adds the relative path, so, I want to know if there is a way to either tell stylesheet_link_tay to use the url, or a helper that returns the url to the stylesheet.
This is for Rails 3.1, by the way
Rails 3.1 uses asset pipeline. If you are using asset pipeline then you need to mention those assets in you application.css. For example in application.css
/*
* *application.css
*= require scaffold
*= require pagination
*= require_self
*= require_tree.
*/
In the above scaffold and pagination should be under rails_root/app/assets/stylesheets ditrectory. For more info check this out http://guides.rubyonrails.org/asset_pipeline.html
Or if asset pipeline is not your issue then check this railcast for HTML Email.
http://railscasts.com/episodes/312-sending-html-email?view=asciicast
You may consider that the <link rel=stylesheet> isn't supported by the mayor providers like Hotmail, Gmail and Yahoo: http://www.campaignmonitor.com/css/
The best option that you have is using <styles> tags in your body or header; or even uglier, using the inline styles, that is supported by most of the email clients today.
Google Mail, in particular, looks for STYLE anywhere in the email and (helpfully) deletes it. And don’t bother to use CSS LINK to a stylesheet. Google Mail, Hotmail, and other email software ignore, modify, or delete these external references to a stylesheet.
http://www.reachcustomersonline.com/2011/12/21/09.27.00/
you can specify the full path of your assets by using
config.action_controller.asset_host = "http://www.yourdomainFORassets.com"
in your environment config file
And you better be careful with the images URL inside CSS files, I have to move everything
to this way to use existing code, check http://guides.rubyonrails.org/asset_pipeline.html
specially with this part:
2.2.2 CSS and Sass
When using the asset pipeline, paths to assets must be re-written and sass-rails provides -url and -path helpers (hyphenated in Sass, underscored in Ruby) for the following asset classes: image, font, video, audio, JavaScript and stylesheet.
image-url("rails.png") becomes url(/assets/rails.png)
image-path("rails.png") becomes "/assets/rails.png".
The more generic form can also be used but the asset path and class must both be specified:
asset-url("rails.png", image) becomes url(/assets/rails.png)
asset-path("rails.png", image) becomes "/assets/rails.png"
http://guides.rubyonrails.org/asset_pipeline.html#in-production
Regards
Related
this post has half the process for using font awesome in a project. The steps are:
download font-awesome zip and extract into grails-app/assets/fonts dir.
modify build.gradle to add includes = ["fonts/*"] under assets
?
Use the font in your code, e.g.
< i class="fa fa-camera-retro fa-4x"> fa-4x
The question is, what is step 3? I assume there are two options:
put something like < link rel="stylesheet" href="path/to/font-awesome/css/font-awesome.min.css"> at the top of your gsp page, but what is the path? I tried guessing, e.g. href="/assets/fonts/css/font-awesome.min.css" but this does not work even after restart.
Put something in application.css. I have no idea what this could be, as it currently only refers to files in its own directory. I even read the manual, but could not figure it out. The manual mentions "*= require font-awesome" but presumably this requires more code somewhere as it doesn't work.
Any suggestions? Grails certainly makes some very hard things easy, but it also makes some easy things hard.
You may have to change the directory references inside the fontawesome.css file. Try for a replace of all the references to ../fonts/fontawesome for fontawesome and check if it works.
This assumes having the font-awesome.css file inside the assets/stylesheets directory and the fonts inside the fonts directory. Then, in build.gradle you should have something like:
assets {
minifyJs = true
minifyCss = true
includes = ["fonts/*"]
}
In your layout GSP file's (main.gsp) <head> you should have something like:
<asset:stylesheet src="application.css"/>
Finally, in your application.css you should have something like:
*= require font-awesome
The require should have the same name as the CSS file without the .css extension. So, if you have the minified version of font-awesome it should look like this instead:
*= require font-awesome.min
Note that by doing that you don't need to add the CSS include to GSP pages.
Alternatively you can just generate an embedding code on the website of fontawesome (http://fontawesome.io/get-started/) and add it to your main.gsp file
<script src="https://use.fontawesome.com/xxxxxxxxxx.js"></script>
I got the answer to step number 3 from here:
The answer is to add the following to application.css
"*= require css/font-awesome"
Surprisingly, this will pull on font-awesome.min.css from the fonts/css/ dir where the files are exploded from the zip distribution.
Jordi and klocker also supplied valid solutions, but the above one is what I was looking for.
How to reference the assets directly via a link is still a mystery.
I have required CSS stylesheets many times in many of my RubyOnRails applications, and actually i need a few things demystified.
What is the difference between:
//=require mystyles
and
*=require mystyles
Both seem to work, so what is the difference?
And is this a part of the asset pipeline or a part of SASS or just plain CSS?
The two examples you gave are exactly the same for stylesheets, however the //= syntax is the only one that works for Javascript. You also need a standard CSS comment at the start (/*) and a close comment (*/) at the end of the require block to make it ignored to anything but the asset pipeline:
/* ...
*= require mystyles
*= require_self
*/
These require directives are only part of the asset pipeline, not CSS or SASS. To include a stylesheet for CSS or SASS, you would use a #import rule as Blieque stated in his comment.
Check out the manifest files and directives section of the Asset Pipeline guide on the Ruby on Rails guide site for a more detailed explanation of the difference. There is also a warning given there that might be of interest:
If you want to use multiple Sass files, you should generally use the
Sass #import rule instead of these Sprockets directives. Using
Sprockets directives all Sass files exist within their own scope,
making variables or mixins only available within the document they
were defined in.
There is no difference, as long as it's a valid comment line, it'll work :)
Instead of having the page include a style tag with a link where to get the css from, which I could add to my view using rails' stylesheet_link_tag helper method, I want to have the css inline directly inside the page.
This is what I came up with so far:
%style(type="text/css")=File.read(physical_asset_path("email.css"))
But I can't find any rails' helper method which gives me the physical path of an asset - physical_asset_path is just a dummy method invented by me.
Anybody knows how to get the physical path of an asset when using rails 3.2.x?
Is there an easier/ better way to get stylesheets - from css files inside the common rails assets paths - inline?
Use case: most email clients don't access external sources (like css, images) without user confirmation. So to get the emails properly displayed I need to embed the CSS inside the emails' HTML.
Rails.application.assets.find_asset('email').to_s will return the compiled asset as a string.
Use premailer or premailer-rails3
https://github.com/fphilipe/premailer-rails3
or
https://github.com/alexdunae/premailer
Joe's Nerd Party say:
We also used the Premailer gem to automatically inline the linked
stylesheet in the email views. Our email layout looks something like:
%html
%head
= stylesheet_link_tag 'email'
%style{:type => "text/css"}
:sass
#media all and (max-width: 480px)
table#container
width: auto !important
max-width: 600px !important
... and so on for the mobile code
%body
Email body here.
%table
Lots of tables.
We include a stylesheet in the HTML. Premailer downloads it, processes
it, and inserts the css rules inline in the HTML.
The #media rules need to be inline in the email layout, since
Premailer can’t handle those being in a separate css file yet.
We use premailer-rails3 to integrate Premailer into Rails 3.
Unfortunately, we found a bunch of bugs in premailer and
premailer-rails3. Our forks of the projects are at
https://github.com/joevandyk/premailer and
https://github.com/joevandyk/premailer-rails3. The forks fix some
encoding bugs, remove some weird css processing stuff done by
premailer-rails3, allow premailer to not strip out embedded
rules in the email layouts, and some other things.
We also found a bug in sass-rails, where you can’t embed image-urls in
inline sass code. See https://github.com/rails/sass-rails/issues/71
Premailer-rails3 hooks into ActionMailer when the email actually being
delivered, not just generated. When running tests, email is not
actually sent, so the premailer-rails3 hooks don’t get ran during
tests. I haven’t spent the time to see if it’s possible to get the
premailer processing to run during tests, but that would be a nice
thing to do.
Also, our forks on premailer-rails3 assume that you want premailer to
go out and actually download the linked CSS files. It should be
possible to use the Rails 3.1 asset pipeline to get the processed css
without downloading it. A very special thanks goes to Jordan Isip who
did the super annoying job of making sure the emails look great in all
the different clients out there. Writing that CSS/HTML did not look
fun.
Update:
Roadie appears to be a better option. Thanks to Seth Bro for pointing it out.
(Sorry this answer is in html, not HAML… but that shouldn't be a problem for HAML fans)
I found this question when looking for a way to inline Sass compiled as css into html for creating html email templates.
Combining the above advice, I used the following code in the head of my html page:
<style type="text/css">
<%= Rails.application.assets['path/to/sass/file'].to_s.html_safe %>
</style>
This code compiles Sass as CSS and then inserts the css into a <style> tag. The html_safe ensures that any quotes (' and ") or angle brackets (> and <) used in the css are not escaped.
The path/to/sass/file is the same as you would use when creating a stylesheet link tag:
<%= stylesheet_link_tag 'path/to/sass/file', :media => 'all' %>
Rails.application.assets['asset.js'] will work only in local environment, as rails asset compilation is disabled in both production and staging environment.
Rails.application.assets_manifest.find_sources('asset.js').first.to_s.html_safe should be used to inline css when using rails asset pipeline.
Can't add comment to Seth Bro's answer. You better use #[] instead of #find_asset:
Rails.application.assets["email"].to_s.
Re "asset will not be compressed". It's not true. It will be compressed if you have compressors enabled (in rails config):
Rails.application.configure do
# ...
config.assets.css_compressor = :sass
config.assets.js_compressor = :uglify
end
Notice, that by default this is enabled in production environment (config/environments/production.rb).
Had the same problem, solved it using #phlegx's answer to a similar issue in Premailer.
For an environment-safe solution you need to use
(Rails.application.assets || ::Sprockets::Railtie.build_environment(Rails.application)).find_asset('email.css').to_s
I've packaged it into a helper in my app:
# app/helpers/application_helper.rb
# Returns the contents of the compiled asset (CSS, JS, etc) or an empty string
def asset_body(name)
(Rails.application.assets || ::Sprockets::Railtie.build_environment(Rails.application)).find_asset(name).to_s
end
I was trying to inline css for use in google amp compatible pages with rails. I found the following helper from vyachkonovalov which was the only thing for me working in production and locally.
Add the following to the erb template:
<style amp-custom>
<%= asset_to_string('application.css').html_safe %>
</style>
And the helper to ApplicationHelper. It works perfectly locally and in production.
module ApplicationHelper
def asset_to_string(name)
app = Rails.application
if Rails.configuration.assets.compile
app.assets.find_asset(name).to_s
else
controller.view_context.render(file: File.join('public/assets', app.assets_manifest.assets[name]))
end
end
tl;dr (without Roadie):
%style(type="text/css")
= render template: '../assets/stylesheets/email_responsive.css'
For actually applying the CSS as inline styles, I recommend roadie-rails (which is a Rails wrapper for Roadie). It also has other neat features like absolutizing hrefs, srcs etc.
A usage combining both inlined (email.scss) and non-inlined (email_responsive.css) stylesheets, both residing in app/assets/stylesheets:
-# This will be inlined and applied to HTML elements.
-# Note that you need to include this in your asset config, e.g.:
-# Rails.application.config.assets.precompile += %w(... email.css)
-# (You need to list it as `email.css` even if it's actually `email.scss`.)
= stylesheet_link_tag 'email'
-# E.g. for media queries which can't be inlined - yeah, some iOS devices support them.
-# This will not be inlined and will be included as is (thanks to `data-roadie-ignore`).
-# `template:` marks it as a full template rather than a partial and disables `_` prefix.
-# We need to add the extension (`.css`) since it's non-standard for a view.
%style(type="text/css" data-roadie-ignore)
= render template: '../assets/stylesheets/email_responsive.css'
You can use this:
Rails.root.join('public', ActionController::Base.helpers.asset_path("email.css")[1..-1]).read.html_safe
I'm trying to allow the user to customize my application using YML files.
When the user updates certain things the CSS needs to be updated as well.
I'd like to solve this problem using dynamic CSS instead. The way I was planning on doing this is to have a settings SCSS file which the other css files import and use.
Here is what I have so far:
settings.scss.erb:
$width: <%= Rails.application.config.width %>px;
main.css.scss:
//= require settings
#import "settings";
#main {
width: $width;
}
But I get this error:
Invalid CSS after "$width: ": expected expression (e.g. 1px, bold), was "<%= Rails.appli..."`
So It seems that the settings are not being passed through the erb parser before being handed off to the SCSS parser, is there any way to solve this.
I'd rather not put everything in .erb files since my text editor doesn't support (syntax highlighting and commands) when having scss in erb files
Side stepping the problem where ERB is not being parsed, you are not going to be able to customize the CSS dynamically (I think the main file may require an erb extension). The asset pipeline is designed to serve assets in a way that tells browsers that the are static and are not going to change.
Assuming the erb parsing was working, the width would be rendered during the precompile phase, or on the first request. If you are using Sprockets far-future headers are set to tell the remote clients to cache the content for 1 year. And Sprockets only picks up changes if the timestamp of the file changes, so would never get any new values.
You could force Sprockets to dynamically serve every request, and to not send any headers, but it is not really designed for this and there are significant performance risks in doing so.
Sprockets official documentation clearly says that:
Sprockets takes any number of source files and preprocesses them
line-by-line in order to build a `single` concatenation.
I'm a big fan of sprockets in Rails but here's the problem - my application has to support multiple layouts(desktop browsers) and mobile clients(iphone, ipad, android phones etc).
Both of this layouts require their own HTML reset CSS rules. Concatenated rules of desktop&mobile reset files would make a conflict because they override low level CSS directives.
How can I fix that?
You can get multiple top-level CSS files by making a Sprocket file for each. For example, say you want desktop.css to be comprised of reset.css, common.css, and ie.css and mobile.css to be comprised of common.css and ios.css. You would have the following files:
app/assets/stylesheets/desktop.css
app/assets/stylesheets/mobile.css
app/assets/stylesheets/reset.css
app/assets/stylesheets/common.css
app/assets/stylesheets/ie.css
app/assets/stylesheets/ios.css
In desktop.css, you would have the following:
/*
*= require reset.css
*= require common.css
*= require ie.css
*/
In mobile.css, you would have the following:
/*
*= require common.css
*= require ios.css
*/
Then, in app/views/layouts/desktop.html.erb, you would do
<%= stylesheet_link_tag :desktop, :debug => Rails.env.development? %>
and similarly for mobile.html.erb.
Lastly, you'll need to set the precompiled asset list in config/environments/production.rb:
config.assets.precompile = %w( desktop.css mobile.css )
I'm not really sure if sprockets supports this but I know that if you use the Jammit gem. You can setup different packages each with it's own cocktail of your JS or css files. e.g. have a :workspace package for desktop and and :mobile package for mobiles.
It is all defined in a config yaml file and it will concat them in the order you list them, which can help get plugin dependencies correct etc.
javascripts:
workspace:
- public/javascripts/vendor/jquery.js
- public/javascripts/lib/*.js
- public/javascripts/views/**/*.js
- app/views/workspace/*.jst
mobile:
- public/javascripts/vendor/jquery.js
- public/javascripts/lib/mobile.js
stylesheets:
common:
- public/stylesheets/reset.css
- public/stylesheets/widgets/*.css
workspace:
- public/stylesheets/pages/workspace.css
mobile:
- public/stylesheets/pages/mobile.css
Jammit might be worth a look for your needs
Hope this helps.
I'm assuming you already have different layouts for each device or device group. If so, just include a different top-level css file in each, then have different require statements in those top-level files. If you're using Rails 3.1, there's no reason you have to keep the built-in line that includes all css files.