Using Asset Pipeline in Rails View - ruby-on-rails

I have a Coffeescript view, something like widget.js.coffee which needs to include jQuery, as I can't be sure that jQuery is available. This idea is for other people to use the JS file, e.g.
<script src="http://my.rails.app/40/widget.js"></script>
My app already has jQuery via the asset pipeline, so I want to do the equivalent of the application.coffee manifest, where I can simply say something like:
#= require jquery
So far, it looks like I can output jQuery via so:
<%= Rails.application.assets["jquery"].source %>
but this seems to break the Coffeescript code (looks like there are backticks in the jQuery source).
I'm not sure the best way to proceed. Any thoughts on the best way to do this?

Make a .coffee file in the asset pipeline that includes all the libraries you require. Let's call it "widget.js.coffee" and it lives in assets/javascripts
In your controller, pull the generated source like so:
code = Rails.application.assets['widget'].source
Compress it
#js_libraries = Uglifier.compile code
Use it in your view. If your view is coffeescrtipt, make sure it is enclosed in backticks
<%= raw #js_libraries %>

Related

How do I pass script name to layout from separate haml file

This is what I'm currently using:
haml :login_signup, :layout => :'main'
From the login_signup haml file, I would like to pass the name of the JS file to be parsed inside the :main haml file.
Reason? layout main.haml contains jquery reference. Rest of the haml files use different JS scripts that require jquery to be sourced first.
What you describe sounds like content_for.
Here is how this works add something like this to your main (source):
= yield(:somejs)
And then fill it from the login_signup view:
- content_for(:somejs) do
= javascript_include_tag :foo
Since you tagged also Sinatra there is a plugin for that functionality: https://github.com/foca/sinatra-content-for

Adding page-specific CSS to Rails Asset Pipeline

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 %>

Use Rails Sprockets directives when rendering js from controller

I want, from a controller, to render a .js.coffee view that includes another js file from the lib/assets/javascripts directory:
#= require doc_ready
Why a view rendered by a controller instead of a static asset?
Because I want to refer to the file through an absolute url, that doesn't changes. Rails 4.0 only compiles assets with a digest like embed-dc589fbef3832d9c38a4fbbc4b021f59.js and I want to use the same url (and possibly expire the cache file based on time), even if I make changes to the script.
Why an absolute url?
Because I want to use the script externally on another website, and the code I give to the webmaster of that site mustn't change.
Why do I want to include another js from the assets?
To keep the code DRY
To require a simple library that simulates the jquery ready event, used to create widgets on the page that included the script.
Can I achieve that by making a controller action that renders a .js.coffee view, which compiles and includes other needed js files from the library, just like sprocket does when compiling assets?
Use redirection like so:
def show
redirect_to view_context.javascript_path('embed.js.coffee')
end
There is a way to render whole js file:
def show
render text: Rails.application.assets.find_asset('embed.js.coffee').body
end
I managed to find a way to do it, by using this answer.
The controller is left untouched:
class Widgets::EmbedJsController < ActionController::Base
def embedded_script
end
end
In the coffeescript view, I have "required" the other file like this:
`<%= raw Rails.application.assets['doc_ready'].body %>`
Seems to work locally, I'll test in production soon.
This can also be refactored by just serving Rails.application.assets['widgets/embed'].body directly from the controller, which should compile coffeescript but have not tested it.
Another approach is to symlink or copy the digest version of the asset to some constant path (and give that to the 3rd party). This has the advantage that the requests shouldn't hit rails at all (since these should be served directly by the web server.
It is relatively simple to automate this - two libraries that I am aware of that do this are
non stupid assets
asset_symlink (I wrote this one)

Moving unobtrusive javascript out of html.erb file

I have a html.erb file in one of my views. The file is pretty big and has about 2/3 javascript code and just 1/3 html. I dont like this file being too cluttered. The javascript part is mostly event handlers and usage of jquery UI components like date pickers, dialogs etc for the corresponding html elements in the page. I would like to separate the javascript part from the html part.
Can I move the javascript to a separate js.erb file and use it like a partial? What is the advantage of this?
How would I move the javascript to a static .js file when I use rails API like I18n.() and <%= form_authenticity_token %>. Should I pass them every time to the wrapping javascript function? Is there a better way to do this?
If I move javascript out of the html.erb file will it help in caching/rendering of html.erb page?
Interested to find out if there are any re-usable patterns
Sample code on the html.erb file:
<% content_for :javascript do %>
<script type="text/javascript">
$(document).ready(function()
{
$('#create_segment_dialog').dialog({
title: "<%= I18n.t("segment.create_segment_title") %>",
// lots of javascript
}
</script>
<%end %>
//HTML starts here
<div id="right-column">
My 2c, but I know there are differing opinions on this:
Try and separate out as much of your JS code into a function or functions and put them into JS files in your asset pipeline. Take advantage of the move to break your JS into re-usable components that could be used by other methods/controllers.
This means you get all the benefits of the asset pipeline for the JS you move there:
Caching & fingerprinting your JS assets
Minification & compression support to save bandwidth
Minification to obfuscate your code if that is something you want
Concatenation of JS files to reduce the number of requests a browser has to make
Possibility to serve the assets from another location (CDN, web tier vs app tier)
Improved DRYness if that JavaScript is used by other methods/controllers
The drawback? As you've pointed out, any Rails variables have to be passed in as parameters to the functions.
Moving your JavaScript to a .js.erb partial is an option, but if this code is very specific to a particular method or controller then it is not necessarily improving DRYness - it may make your code a little more readable, by separating HTML and JS.

Rails with backbone-rails: asset helpers (image_path) in EJS files

I have a Rails 3.1 app that uses the codebrew/backbone-rails. In a .jst.ejs template, I would like to include an image, like so:
<img src="<%= image_path("foo.png") %>"/>
But of course the asset helpers are not available in JavaScript.
Chaining ERB (.jst.ejs.erb) does not work, because the EJS syntax conflicts with ERB.
Here is what I know:
The asset helpers are not available in the browser, so I need to run them on the server side.
I can work around the problem by making the server dump various asset paths into the HTML (through data attributes or <script> and JSON) and reading them back in JS, but this seems rather kludgy.
Is there a way to somehow use the asset helpers in EJS files?
There is a way, actually, to chain a .jst.ejs.erb file, although it's fairly undocumented, and I only found it through looking at the EJS test cases. You can tell EJS to use {{ }} (or [% %] or whatever else you want) instead of <% %>, and then ERB won't try to evaluate your EJS calls.
Make sure to require EJS somewhere in your code (I just included gem 'ejs' in my Gemfile), and then create an initializer (I called it ejs.rb) that includes the following:
EJS.evaluation_pattern = /\{\{([\s\S]+?)\}\}/
EJS.interpolation_pattern = /\{\{=([\s\S]+?)\}\}/
Then just make sure to rename your templates to .jst.ejs.erb, and replace your existing <% %> EJS-interpreted code with {{ }}. If you want to use something other than {{ }}, change the regular expressions in the initializer.
I wish there were an option in Sprockets to handle this through the config rather than having to explicitly include EJS, but as of the moment, there's no way to do that that I know of.
I can see two ways. Neither are great.
When you say <%%= variable %> then this is rendered by ERB as <%= variable %>, so you could double percent escape everything but the asset_tags and that would survive the trip through one ERB pass on the way to EJS.
If you find that too gross...
How about making a different javascript file, with an ERB extension, that defines your asset paths? And then use the asset pipeline to require that.
So say assets.js.erb defines something like:
MyAssets = {
'foo': <%= image_path("foo.png") %>,
...
}
And then require this somewhere near the top of your manifest. And then reference the globals however that works in EJS.
For those willing to try HAML instead of EJS: Using haml-coffee through haml_coffee_assets has worked well for me as well.
You can have the following in a .hamlc.erb file:
%img(src="<%= image_path('foo.png') %>")
(It still doesn't give you routing helpers though, only asset helpers.)
Ryan Fitzgerald was kind enough to post a gist of his JavaScript asset helpers (which get precompiled with ERB): https://gist.github.com/1406349
You can use corresponding Javascript helper via the following gem:
https://github.com/kavkaz/js_assets
Finally (after installing and configuring) you will be able to use it like this:
<img src="<%= asset_path("foo.png") %>"/>

Resources