How can I run specific compilation tasks with rails/asset pipeline/sprockets within my application?
Basically, I have sets of user created css for an application; users upload css for their parts of the application (security considerations aside etc, already handled). How do I run a task to compile specific css sets into the main css I have? This is not a live compilation issue, I just want to take an input, compile that to a file, and serve that that on demand, which is more a 'I need this set of css precompiled at will when I want to precompile it within a running application'
I'm updating something implemented previously where I was able to haphazardly serve user generated css, I'd like to integrate this with the asset pipeline. How can I get greater control over the asset pipeline? I'm assuming I need to learn more about Sprockets, but I'd be curious what anyone could add to assist.
Per user CSS files would be possible, but to use Sprockets and the pipeline in the intended way to generate the files is going to take a bit of messing about.
To generate a user CSS file you are going to have to:
1. Generate a manifest for the user.
The manifest would include the main css via a sprockets directive, and require self at the end along with the user css.
The manifest file would need a name that is unique to the user
2. Compile the manifest.
You won't want to compile them all, so you'll need to write something to do just the one you want.
3. Add the new manifest to the pipeline manifest
This is a YAML file that holds the mappings between the name of manifests and files in the pipeline and their hashed counter-parts. You'll need to add your new (or updated) file hash to this without clobbering the other entries.
4. Restart your app.
This is required because Rails read in the pipeline manifest when it starts up, so you would not see any changes you'd made until this occurs.
==
Then you will be able to reference the username based CSS file for the user.
The with this approach is that each time you deploy the custom manifest would be overwritten.
If you are storing the user's custom CSS in the database you could write out the custom user manifests at each deploy.
Another approach is to use the pipeline for the main CSS and ignore it completely for the user CSS, just doing what you do now. Use on link for the pipeline CSS and a second for the user CSS. You could still minify the CSS when the file is created, but if the extra request is out of the question then something based on the above.
Best of luck!
Related
Before executing Asset Precompile (rake assets:precompile) I want to apply gulp tasks to my JavaScript files which are located here:
app/assets/javascripts/my_angular/directives/*.js
app/assets/javascripts/my_angular/controllers/*.js
So when I later run rake assets:precompile it will pick already processed-by-gulp files.
But the problem for me is that I do not want to simply overwrite existing JS files with its gulp output files since I still need original, not touched files for comfortable development.
I think I need to have two folders:
1) development_assets
2) production_assets (auto-generated folder with gulp output)
Is it possible in Rails to have different assets directories for different environments? (development, production). If yes - how to configure it?
Maybe there is another solution for my problem? Without having two separate directories... I am open to suggestions.
You can configure the assets path with config.assets.prefix = '/gulped-assets'. If you do that in config/environments/production.rb, it'll apply to production but not development, letting you still use your original files in dev. You'll need to either make sure your deploy process runs Gulp before asset compilation, or run Gulp locally and include /gulped-assets in your repository.
You can also add a preprocessor to the asset pipeline, which would leave you needing just one /assets directory. You do that by specifying a file extension and a handler, then adding the extension to all the files you want processed that way, just like you have with .sass, .erb, etc. To crib from the Rails examples, it looks like this:
module BangBang
class Template < ::Tilt::Template
def prepare
# Do any initialization here
end
# Adds a "!" to original template.
def evaluate(scope, locals, &block)
"#{data}!"
end
end
end
# config/initializers/bang.rb
Sprockets.register_engine '.bang', BangBang::Template
Then any file containing .bang in the extensions will have a ! appended to it. There's already support for a lot of different tasks out there, so perhaps you can avoid Gulp in favor of a Sprockets-only pipeline. Depending on your Gulp tasks, you might even be able to shell out and run data through them to build a hybrid pipeline.
Or, you can go the other direction and replace Sprockets with a Gulp-only pipeline. There are a lot of people doing that, and anything I'd write here would be long and only duplicate their work, so check out the gulp-rails-pipeline gem and perhaps read Gulp - a modern approach to asset pipeline for Rails developers for another angle on it.
So that I could take advantage of all the already well developed front-end tools like requirejs, bower and grunt... It's just that so many of them somehow get crippled going with rails.
Primary advantages:
It is easier to load third party scripts this way. It is always possible and sometimes easy to put these through the asset pipeline, but it is also often tedious and you lose bower.
Scripts in public will not be digested, so they can be loaded by non-rails pages easily. For example, you use a javascript file on your site, and also need to load it on another, e.g., PHP site, or need to allow other people to load your script for an embedded API, etc... then you'll need to serve from public.
Primary disadvantages:
Because you're not using the asset pipeline you lose:
Asset combining and compression. Asset pipeline CSS and Javascript will be loaded in a single HTTP request each, and the content can be minified. This makes first page load on your site faster, especially if you have lots of client code or a site that needs to be super snappy for occasional visitors.
Digesting. The asset pipeline protects you 100% from cache vagaries and potentially having different users seeing your site with different version of your assets. Once you deploy, every visitor will get the new assets.
Relatively automatic etagging. Once those visitors get the new assets, their clients will generally cache them for a long time. Rails can afford to let assets cache essentially forever because digesting ensures you're not punished for this later.
So there are pros and const both ways and neither is right or wrong.
It's just that so many of them somehow get crippled going with rails
Pipeline
The reason is you're not meant to use the likes of Grunt etc with Rails. Rails' asset pipeline is only meant to contain the files which can be precompiled & used directly in your application:
The asset pipeline provides a framework to concatenate and minify or
compress JavaScript and CSS assets. It also adds the ability to write
these assets in other languages and pre-processors such as
CoffeeScript, Sass and ERB.
This will typically mean compiled third party JS/CSS files, and your own application JS/CSS files. I don't see how something like Grunt would provide any benefit to this? All it does it create a way for you to manage dependencies, versioning & source of particular assets?
--
Public
Using the files in your public folder isn't such a big deal. One of the most prominent things it does do is to exclude those particular files from the file digest processs, allowing you to use the likes of endpoints (scripts) which can be accessed by other services (outside the scope of routes.rb)
A good example of this is when we created an analytics system, and put the analytics.js into the public folder, so all the widgets could access it. This allowed other sites to access this file, regardless of the state of the asset pre-compilation.
One caveat to this would be you could perhaps have some way to store a "pseudo" file in the public folder, with it routing dynamically (with ERB) to the precompiled equivalent, but I've got no experience with this
--
Pipeline
The benefits of keeping your assets inside the asset pipeline, as stated by gwcoffey, are:
They will be compiled as you design (I.E primarily into application.js, but also into any other files you define too)
You don't need to worry about versioning (every precompile is basically a way to better the version without worrying about grunt etc)
You can include as many dependencies as you want - meaning you're able to create a totally modular set of assets which can be used throughout your app; rather than single scripts which will have their own dependency base
Recommendation
Unless you maintain third-party scripts which need dependencies to run, I would not recommend using Grunt for Rails. If you develop your own JQuery / Javascript scripts, by all means run them through Grunt etc; but for use in your app, I'd steer clear
Hope that helps!
We have a Grails app with loads of javascript files in the /web-app/js folder and we recently installed the Asset Pipeline Plugin... but just recently. The app is a few years old now.
We don't want to move all js files from /web-app/js folder to /grails-app/assets/javascripts folder since we might break some of the gsp files that are using those resources directly.
Let's suppose we have the file:
/web-app/js/myscript.js
We want to create a matching file in the assets folder...
/grails-app/assets/javascripts/myscript.js
... but that file should be empty except for one line like:
//=require /web-app/js/myscript.js
So the file in the assets folder only points to the real file in web-app folder.
The problem is that the above manifest line does not work.
The above might not make too much sense for just one file. But what we really want is to include several files (that already exist in /web-app/js folder) and use the Asset Pipeline Plugin to compile them all.
Is it possible?
Thanks a lot.
Unless the default changed in the more recent versions of the asset pipeline, just lose the /web-app prefix - the plugin searches both locations for compatibility reasons (think of all the plugins that aren't asset pipeline aware and would have to be modified..)
EDIT: in fact, looking at the Asset Pipeline documentation, you can loose /js as well since all folders under /web-app will be searched for the referenced file name.
I am new to rails so this is probably a simple question about using the asset pipeline.
In my app, I want to use this jquery plugin: http://www.fyneworks.com/jquery/star-rating/
So to do it, I included the following gem in my gemfile: https://github.com/RichGuk/jquery-star-rating-rails
However, I find that the image used for the star ratings is too low resolution and I'd also like to change the style. However, all 3 versions of the stars that are displayed are held in one image so I'd have to play around with the scripts as well to make sure they are configured properly if I make the image for the stars larger.
Back to my question: How do I edit this image file in my application?
I've tried downloading all the files and putting them in my vender directory and editing the file but it did not seem to work.
I know the files are included by the gem but how do make the files visible to edit?
Appreciate the help!
So the asset pipeline consists of potentially many directories (assuming you are using gems that inject their own assets into the pipeline). When an asset is being grabbed in Rails, Rails goes through these directories (in the same order, every time) to find the asset. When the name of the file is first found, that's it, Rails grabs it and uses that file.
Vendor asset directories are specified after app assets, I believe. So, if you place the image that you want to change in the app/assets/images folder, you'll essentially be overriding that vendor image in your application with your own image since Rails will search it's own app/assets first. Obviously, the files need to be named the same.
Try adding your star image in your assets path. It seem to
reference star.gif using the asset_path
I would also try
overriding the star plugin by creating your own css file.
After I deployed my upgraded Rails 2.3.x -> 3.1 (rc4) app to our test environment this afternoon, all of our stylesheets and JavaScript files were returning 404 errors. We had added the rake assets:precompile task to our post-deploy script and it took a while to determine why the assets folder didn't have the pre-compiled files we expected.
In the end, the files weren't being compiled because apparently only application.css and application.js (+ non JS/CSS files) are processed by default.
We needed to change the following configuration value as follows:
config.assets.precompile += %w( *.js *.css )
Question: why isn't this the default?
I would have expected that anything that wasn't necessary to process as a manifest file would just get copied into public/assets. Much of what I've read on the asset pipeline is essentially "stick your assets in app/assets, configure the manifest files, and it should just work". Since the assets:precompile task didn't spit out any information about what it was doing, it took a while to determine that it just wasn't looking at the files we thought it would.
Is there any reason why this would not be a good value for the precompile configuration?
Thanks!
The idea is to have all your JavaScript and CSS always loaded in one shot, rather than loading bits and pieces as you move along. That way you always have the 'world' loaded and ready to work with, rather than having to include a whole bunch of individual files here and there.
It's a bit of a larger 'up front' load, but then the browser should keep loading all the javascript from cache. So the perceived speed of the site should speed up due to having everything cached and ready to go after the first request.
This was a controversial decision to include for Rails, but so is including CoffeeScript by default. Rails has always been an opinionated framework that way.
the new sprockets-based pipeline compiles all the files in /asssets/stylesheets and /assets/javascripts get compiled into application.css and application.js, respectively, by default.
In your views, you only need to link the application files, sprockets handles the rest.
Update:
Well, you don't have to make it all into just one file... You could have an shared.js, secure.js and public.js and have them each include the parts they need...
Think of them not as javascript files, but manifest files that establish groups of javascript files which you can then include as a group with a single javascript_include_tag. While the default is to include everything in the folder into a single file, you can be always pick and choose what to include, and what not.
The 'precompile' task simply runs those manifest files and compiles the multiple files into one, while pre-processing and sass or coffee script it runs across.