I've an app which works fine in development and on my current production server.
I want to move it to FREE heroku (basic config: 1 dyno, 1 worker).
Unfortunately, the pdf generation (using PdfKit) is ok BUT without the pictures defined in my CSS.
I've followed a lot of tips including:
http://blog.mattgornick.com/using-pdfkit-on-heroku
http://jguimont.com/post/2627758108/pdfkit-and-its-middleware-on-heroku
http://code-fu.pl/blog/2011/05/17/pdfkit-heroku
Thoughts?
Found a workaround but I am still eager to know a better option:
I duplicated my view: one dedicated for html, another for pdf.
I removed all css using pics and put it in a separate file, included only in the view dedicated for html
finally, I inserted the css in the view dedicated to the pdf:
.foo { background-image:url(<%= Rails.root %>/public/images/bar.png) }
Very Ugly but works so please tell me if you've better
It's probably an issue with the way the url's are specified in the css. As I recall, they should be file system absolute paths. What does your css look like?
Here is how I answered my needs with:
Just one single view file
Just one css file
The trick was to pass the proper base_url to the css file dynamically, given I expected a pdf or html.
I decided to use LESS. Style compiles css in a different manner, given the base-url I provide in the DOM. This base-url is generated by a helper.
Here were my steps:
changed my style.css to style.less
Added to my view:
<%= stylesheet_link_tag "style.less", :rel => "stylesheet/less" %>
<script id="base_url" type="text/javascript" data="<%= assets_path %>"></script>
<%= javascript_include_tag "less.min.js" %>
In my helper:
def assets_path
if request.fullpath.include? ".pdf"
"#{Rails.root.join('public',"images","pictos")}"
else
"#{request.protocol}#{request.host_with_port}/images/pictos"
end
end
and in my style.less:
#base_url: `document.getElementById('base_url').getAttribute('data')`;
.foo { background-image:~"url(#{base_url}/bar.png)" }
Related
This is a question that several people have asked before, but none of the questions were quite asked or answered in a way that I found helpful, so I'm writing the question and answer that I would have found helpful.
I have a Rails 3.1+ app using the asset pipeline. There's one specific action that I want to have use different CSS. (In my specific case, I have a page that is intended to be printed, so it truly needs completely different CSS and does not need any Javascript.) Currently, I have only one application-specific CSS file. How do I add the new CSS file and direct the asset pipeline to use my file?
For example, right now, my app/assets looks like
app/assets
/javascript
application.js
custom.js.coffee
/css
application.css
custom.css.scss
I want to add a print.css file that is used by the view of a specific action. This view will not use the application.css file. How do I add print.css?
I found this blog post to be very helpful: http://blog.seancarpenter.net/2012/11/05/page-specific-javascript-with-the-asset-pipeline/. My answer paraphrases what this blogger already wrote and fills in a few missing details.
First, it's important that you've read and understood the Rails Guide to the Asset Pipeline. Unfortunately, this guide doesn't clearly explain how to add action-specific assets, but it does cover some concepts you need to know. Made sure you understand these ideas:
That the asset pipeline compiles Javascript, CSS, and other assets so that Rails servers can cache assets for better performance.
That manifest files use commands like require, require_tree, and require_self to indicate which files are compiled together.
That in order for the asset pipeline to work properly in production, you need to manually run rake assets:precompile to produce the compiled, minified assets in the public directory.
These ideas are the minimum "need-to-know" pieces of information about the asset pipeline. If you don't already understand these ideas, you don't have an "expert or enthusiast" level of knowledge about the pipeline, and unfortunately, SO isn't the right place to learn this stuff. Fortunately, the the Rails Guide to the Asset Pipeline is a short 15-minute read and can get you up to speed quickly if you need it.
Second, these are the changes you need to make in order to ensure that the asset pipeline correctly sees and handles your new print.css file.
Follow these steps:
Add your print.css file to app/assets/css.
You'll need to create a manifest file that will show Rails where to find print.css. You need to do this, even though you only have a single CSS file you're adding. This is an easy step:
Add a file called print.js to app/assets/javascript.
Add this line to print.js:
//= require print
This will be the only line in the entire print.js file. If I understand correctly, Rails expects manifest files to have the file extension .js, which is why we aren't using print.css as the manifest file.
We now need to instruct Rails to find and use the print.js manifest. Add the following line in your config/application.rb file:
config.assets.precompile += %w( print.js )
We're almost finished! However, the already-present application.js manifest includes the line //= require_tree . which means that it will include your print.css file. This will cause your print.css styling to affect your entire site, not just the single view. There are two ways of dealing with this:
If application.js and print.js do not share any assets, you can use the stub command in your application.js to exclude the assets used in print.js. What this does is instruct application.js to remove any of the assets that print.js references from its own list of referenced files. Our modified application.js looks like:
(snip...)
require_tree .
stub print
See this answer for more information.
If your print.js and application.js files share some assets, you'll need to move all of the assets used by application.js into subdirectories. I didn't do this myself, so I'm not the most help in this area. Look at this answer for instructions.
Now we have included print.css in the asset pipeline. We now need to direct Rails to use print.css in your specific view.
Let's say your action is in the reports controller, and that the action is named print_reports. This means we have a reports_controller.rb file and a print_reports.html.erb (or .haml) file. We need to make several changes to these files.
To start, add a new layout in app/views/layouts. Perhaps call it print.html.erb. We'll use this new layout for your print_reports.html.erb file. Set it up as you desire. For a page intended to be printed, this will likely be very simple, such as
<html>
<head>
<title="Print">
</head>
<body>
<%= yield %>
</body>
</html>
Using a separate layout the disadvantage that it's difficult to keep this layout and the layout used by the rest of the application in sync, but if you are using separate CSS files for the action, it's unlikely that you want the layout to be the same anyway.
Add a stylesheet_link_tag in the layout's header pointing to your print.css:
<html>
<head>
<title="Print"/>
<%= stylesheet_link_tag "print" %>
</head>
<body>
<%= yield %>
</body>
</html>
In the controller, we'll tell Rails to use our new layout for the action. Add the line layout 'print', only: [:print_reports] to your controller:
class reports_controller < ApplicationController
layout 'print', only: [:print_reports]
#snip
See this question for more information and a few different approaches.
At this point, when you run the app, your print_reports action should be using print.css correctly!
Remember to run rake assets:precompile before deploying on the server.
Official Solution
It is documented in the official Rails Guides here: http://guides.rubyonrails.org/asset_pipeline.html#controller-specific-assets
Actually you can leave out the require_tree directive (located in application.css and application.js) then use this in your template:
For controller specific JavaScript:
<%= javascript_include_tag params[:controller] %>
For controller specific CSS:
<%= stylesheet_link_tag params[:controller] %>
All of you are putting very complicated answers.
1 Go to app/assets/stylesheets
2.Make a file with the extension .css
3.Go to config/initializers/assets.rb
4.Put this line of of code Rails.application.config.assets.precompile += %w( file.css )
5.Replace file.css with the file you created
6.Go to your html.erb file
7.Type this in the <head>, <%= stylesheet_link_tag "file" %>
8.Replace file with the filename(no extension in the name)
Good Job you linked the file!
There's one specific action that I want to have use different CSS.
Here's an alternative way to accomplish what you're looking for:
Add the controller name and action name to the app body in your /views/layouts/application.html.rb:
<body class="<%= controller_name %>-<%= action_name %>">
<%= yield %>
</body>
Then in your .scss file:
.controller_name-action_name {
// your css goes here
}
So if your controller was static_pages and your action was home:
.static_pages-home {
// your css goes here
}
Tada! Your css only appears for that specific action.
In your layout
<head>
// ...
<%= yield :stylesheets %>
</head>
In your view
<%= provide :stylesheets do %>
// your page-specific css
<% end %>
So I'm kinda lost here. All my CSS/SCSS files are loaded everywhere on my app. But I have two different design (front and back) that I want to separate. How can I achieve that ?
Plus it's kinda useless that all js/css are loaded, even where they are not used. How can I control that ?
What you're wanting to do is control your layouts.
As your question is currently it's too broad for someone to give you a decent specific answer, it's like saying 'tell me about astrophysics, I don't understand how to launch a rocket right now'.
I would suggest to start with the rails guides relating to layouts and then come back with a more specific question once you have a better understanding.
http://guides.rubyonrails.org/layouts_and_rendering.html
There is also a great 11 minute video on RailsCasts which will help you understand and control the assets pipeline: http://railscasts.com/episodes/279-understanding-the-asset-pipeline
Where you are heading is say your app was about managing projects.
Make a copy of the application.css file called say project-manifest.css and use the same structure as that application.css for loading just the stylesheets you want.
Make a copy of views/layouts/application.html.erb to say projects-layout.html.erb
In the new projecs-layout file, update the reference to the css to point to project-manifest.css
Point your controller code to use your new layout
say you have:
# app/controllers/ProjectsController.rb
def show
# code here
# rails does a default render layout: 'application', its overwritten by adding an explict render
render layout: 'project-layout'
end
In your application.js and application.css there is a directive by default: require_tree. It will load all your js and css files to be precompiled later. This is done to make the clients to download the assets packet only once (as it will be cached by the browser) and make the app faster.
If you want to load specific javascript or stylesheet files for each controller, remove the require_tree directive and include them in their respective controller:
<%= javascript_include_tag params[:controller] %> or <%= stylesheet_link_tag params[:controller] %>
Check this out: http://guides.rubyonrails.org/asset_pipeline.html#controller-specific-assets
If I have Javascrips/CSS files from an ASP .NET Project and I want to put them in my Rails project. Where's the best place to put them? Do I need to change every url into <%= asset_path "img" %>?
Put it in assets folder and add below line in views:
To add CSS files:
<%= stylesheet_link_tag "test.css" %>
To add JavaScript files:
<%= javascript_include_tag 'test.js'%>
Building on #Unknown's answer:
Yes, you do need to use asset_path, or one of the sprocket helpers, to refer to your assets in your CSS file so that they will properly include the MD5 fingerprint. Plus, this way you get the right asset between development and production (since they don't live in public while in development). Here's the relevant guide: http://guides.rubyonrails.org/asset_pipeline.html#coding-links-to-assets
According to http://railsapps.github.io/rails-javascript-include-external.html
The best practise for DRY and speed (according to article above) is to download all files to your projects assets folders, put them in the assets pipe for each application.js/.css and let rails compile them into one application.js and application.css in production mode. There are several ways to do this in detail (see link) The preferred way according to article for speed and DRY-practise is to call all js and css from application.css/.js and not put stylesheet_link_tag, calling css or js from view-files. This even though you may have one specific user.js which you only want to use on users page. Though there are ways to load specific files into specific views (see article for details)
Ecxept from having to call them in once in head of application.html(.haml/.erb):
= stylesheet_link_tag "application", :media => "all"
= javascript_include_tag "application"
If you are calling files in css eg. an image, as long as you have the image in "assets/images" you only need to refer to the images as 'image.jpg' in your css/js-files.
I know that most CSS codes go under app/assets/stylesheets, but I have some snippets of CSS codes that are specific to only certain pages. For now, I just have these small CSS codes included in the view files, but I feel like there's ought to be a better way of handling this.
Any suggestion?
Rails convention is to put these in controller specific CSS files:
For example, if a ProjectsController is generated, there will be a new
file at app/assets/javascripts/projects.js.coffee and another at
app/assets/stylesheets/projects.css.scss. You should put any
JavaScript or CSS unique to a controller inside their respective asset
files, as these files can then be loaded just for these controllers
with lines such as <%= javascript_include_tag params[:controller] %>
or <%= stylesheet_link_tag params[:controller] %>.
Putting the CSS inside the views isn't a good idea as you lose features (fingerprinting, auto minification) that the asset management in Rails provides.
Read more here: http://guides.rubyonrails.org/asset_pipeline.html#how-to-use-the-asset-pipeline
what is the best/most efficient way of creating dynamic CSS with Rails. I am developing an admin area on a site, where I would like a user to be able to customize the style of their profiles(Colour mostly), which will also be saved.
Would you just embed ruby script in the css file?
Would you need to change the file extension from css?
Thanks.
In Rails 3.1, you can have your stylesheets pre-processed by erb.
Now let's say you have some dynamic styling called dynamic.css.scss.erb (the .erb at the end is important!) in app/assets/stylesheets. It will be processed by erb (and then by Sass), and as such can contain stuff like
.some_container {
<% favorite_tags do |tag, color| %>
.tag.<%= tag %=> {
background-color: #<%= color %>;
}
<% end %>
}
You can include it like any stylesheet.
How dynamic should it be?
Note that it will be only processed once, though, so if the values changes, the stylesheet won't.
I don't think there is a super efficient way to do have it completely dynamic yet, but it is still possible to generate the CSS for all requests. With this caveat in mind, here's a helper for that in Rails 3.1:
def style_tag(stylesheet)
asset = YourApplication::Application.assets[stylesheet]
clone = asset.class.new(asset.environment, asset.logical_path, asset.pathname, {})
content_tag("STYLE", clone.body.html_safe, type:"text/css")
end
Here's how to use it:
First, copy the above helper in app/helpers/application_helper.rb.
You can then include it in your page as follows:
<% content_for :head do %>
<%= style_tag "dynamic.css" %>
<% end %>
The rest of your page.
Make sure that your layout uses the content :head. For example, your layout/application.html.erb could look like:
...
<HEAD>
....
<%= yield :head %>
</HEAD>
...
I found this out thanks to this post.
You can use ERB with CSS, you just need to render css in the controller. However, for such a heavily requested resource, I do not recommend generating this every time. I would store the users stylesheet in memcached or redis, and recall from it when the page loads, rather than rerendering the file each time. When they update their style, you can expire the cache, just make sure it gets rebuilt when the page renders.
There has been a lot of development over the years, and I recently figured out how to do what this question is asking. And since it has been about 9-10 years since someone has answered this, I thought that I would put in my 2 cents.
As others have said, it is not good practice, and thus can not be done, to put ruby code directly into the CSS file as the CSS is precompiled and is not able to be dynamically changed within the file.... BUT, it can be dynamically changed outside the file!
I will need to give a quick synopsis of CSS variables in case future readers do not know how to use them.
CSS has the use of variables within its coding language to make it easier to change a lot of elements at one time. You put these variables at the top of the CSS file in a root section. Like this:
:root {
--primary: #0061f2;
--secondary: #6900c7;
}
Now, anytime you want to style an element one of those colors, you can simply put var(--variableName) like this:
.btn{
color: var(--secondary);
background-color: var(--primary);
}
.h1 {
color: var(--primary);
}
You can see how it would then be much easier to change the variable in the root section and thus change all other instances within the CSS.
Now for the dynamic Ruby part.
In the <head> section of your application file (or in the case of this question the file that holds the template for the admin's dashboard), you will need to redeclare the CSS variables with your dynamic variables and mark them as important. For example, let's say that you allow your user to choose primary and secondary colors for their dashboard and they are stored in the user's profile called like: user.primary_color and user.secondary_color. You will need to add this to your <head> section:
<style>
:root{
--primary: <%= user.primary_color %> !important;
--secondary: <%= user.secondary_color %> !important;
}
</style>
This !important tag will override the variables found in the CSS file thus dynamically allowing the user to change the CSS and view of their dashboard and have it remain persistent (as the values are saved in their profile).
I hope that this helps future developers.
Happy Coding!
Currently there is a lot of options to generate dynamic css in rails.
You can use less css - is an extension to CSS with extra features.
Gem Less css for rails provides integration for Rails projects using the Less stylesheet language in the asset pipeline.
If you are using twitter bootstrap you may check this out less rails bootstrap.
Also you can use one more CSS extension language Sass for generating CSS. Here is a Saas rails gem.
Check out Dynamic CSS in Rails and Render Rails assets to string blog posts and article about Asset Pipeline
Related SO questions:
Best way to handle dynamic css in a rails app
Dynamic CSS in Rails asset pipeline, compile on fly
Rails: change CSS property dynamically?
I just built this for another site. I have a controller action and a view that pulls color values out of the database, then renders a customized CSS based on the current user's account. To optimize, I am using the built in Rails page caching, which stores a copy on disk and serves it as a static asset. Nice and fast.
Here's an example from the ERB code
#header { background: <%= #colors["Header Stripe Background"] %>; border: 1px solid <%= #colors["Header Stripe Border"] %>; }
#header h1 {color: <%= #colors["Headline Color"] %>; }
#header p a { background: <%= #colors["Control Link Background"] %>; color: <%= #colors["Control Links"] %>;}
#header p a:hover {background: <%= #colors["Control Link Hover"] %>; text-decoration:underline;}
This solution defines some constants in config/site_settings.rb, which can then be used throughout the Rails application, as well as for automatically generating the CSS files whenever the Rails app starts and the CSS input files have been modified..
http://unixgods.org/~tilo/Ruby/Using_Variables_in_CSS_Files_with_Ruby_on_Rails.html