Add subdirectories to Rails assets - ruby-on-rails

I am trying to integrate a Bootstrap framework into a Rails project. The framework comes with lots of html templates which I would like to use. Each template has several links to assets (css, images, js) which are all named something like:
href="assets/css/stylesheet.css"
By including the framework's files in the Rails vendor/assets folder I can access all these resources if I rename them all to
href="assets/stylesheet.css"
or using a Rails helper, but I don't want to have to do that for every single asset because I'd rather leave as much of the framework intact as possible for updates and such, and besides that would be super annoying to deal with.
Is there a way to have Rails access these files the way they are currently written?
(I know for example this is possible with Laravel Elixir).

The standard procedure here is to add references to these in your application.css or equivalent file. There's usually a comment in that master file that looks like this:
/*
*= require_tree .
*= require_self
*/
You can add other files to that manually, or just put your assets in there in a way that they get hoovered up properly by the asset pipeline.
Doing this means they all get packed down into the same distributable CSS file when you roll this out to production.
If you do want to compile this separately for whatever reason you need to alter config/initializers/assets.rb and add things like:
Rails.application.config.assets.precompile += %w[
assets/stylesheet.css
]
That will force-compile another unrelated asset.

Related

Rails project with React Rails directories?

Image showing my rails structure for react
I have a lot of react components and wish to simply keep them better organized. So I'll cut to the chase and just ask. Is it possible to put my react components in directories and if so- how do I select them in a view and other react components?
I've already tried a few variatians like the one below without success and fear that it's simply not possible? Can't find any documentation about this either.
<%= react_component('OutfitCreate.Images') %>
Edit: To clarify, I want to make it clear that I'm using a typical rails project structure, and for react I am making use of the react-rails gem to handle my components as well as generating them.
Edit2: To clarify further, what I'm seeking is a way to target a react component by directory as such:
<%= react_component('<directory>/<classname>') %>
where each directory will be sub directories of "components".
I know this is an old question but maybe it helps anyone. You can do it like this:
<%= react_component "ComponentFolder/ComponentClassName" %>
It works just fine with rails-react and webpacker.
I recently used the react-rails gem and had a good experience. It takes care of accessing your components in Rails templates and does a few other nice things.
To answer your question specifically, you can put your components inside as many directories as you like as long as you follow the gem docs. The gem provides a view helper that allows you to render a specific component, and to pass data to it as props (the helper takes a hash which becomes the component's props).
Edit -- I'm not sure if you're already using the gem, the helper method you are using looks like it, but you don't specifically mention it. Perhaps there is a problem with the gem installation and/or setup. You need to edit application.js and also to run the generator task: rails g react:install
Edit -- To make sure you can access components in the components subdirectory, you should do the following things:
*run the generator: rails g react:install
*make sure the generated components.js file contains: //= require_tree ./components
*make sure your application.js file contains:
//= require react
//= require react_ujs
//= require components
React components will be considered global, because all .js will be minified in one single big .js file. So, you will have to take some considerations.
First, in your sprockets file (Normally application.js) you need to tell Rails to serve the React Components you want. The easy way would be to require all folders and files in components folder, because all your components will be there, but organized in subfolders. This is made adding the next line:
// File: app/assets/javascripts/application.js
//= require_tree ./components
Second, if you want to use your React component named for example Images, which could be defined in ../components/folder/images.js, you just could use in your Rails View the helper react_component('Images') like usual.
React will find the Images component if it match with the Images component you defined inside some served .js (But a sane human will expect you defined the Image Component inside some images.js) because this name Images is global (Remember? One big .js file will be served).
With this approach, the client will download only one big .js file with all your React Components. Bad for download speed, but could be cached.
So, here, you would have to take care to name all components with a different name each one.
Now, if you have for example a component named Foo inside ../components/folder/doesnt_matter.js and another component with the same name Foo, but inside ../components/another_folder/this_neither.js, you will have to tell Rails which file do you want to serve for the specific View you want to render to evade collision name problems.
This means, you could make the client to download only the needed js code (and the needed React Components) for the rendered page. It will be downloading .js files for each page, losing the cache possibility.
One intermediate way to do this, would be to serve a middle sized .js file for all the views in the same controller.
To do this, you could organize your js (or jsx, or ...) in a way you could have a place for common Components (which are used in two or more controllers), and a specific folder for each controller with specific React Components in there.
First, you will have to replace the previously added //require_tree ./components in application.js with //require ./components/common/ for serving only the common React components to All Views.
Second, in your layout, you could serve two js files; an application.js and a #{controller_name}.js (This means, one specific .js file per controller).
Third, for each controller, you will have a .js file with the same name. So, supose you have a controller called home_controller, then, you will need to have a home.js (controller_name helper in layout view will make rails to look for this file) and in it, using sprockets again, you will serve specific React Components with //require ./components/home/
In this way, you will have to take care of your organization, and the React Components Names need to differ with the ones inside .../components/common/.
If you want to be more specific yet, you could use the same technique in layout in combination with controller_name and action_name helpers. Or you could use content_for asking for the specific .js files that have the React Components the View needs.
However, you need to be carefull because i don't know how crazy the Assets Pipeline could turn against you. Specially using content_for.

What is the proper way to link big template assets into rails erb files?

I am developing a rails application starting from webarch template. I know that adding the whole assets folder in the public/ folder will link the assets with my views, but it would not be taking advantage of the assets pipeline functions. The template has a lot of plugins and different options and one generally does not use all of it. The assets folder's size is 30MB.
I though about putting it inside vendor/assets and using it with the asset pipeline but this generates two problems:
I would be serving 30MB of minified code and using a small percentage of it in my app.
I would have to manually rewrite the whole assets folder to use links the way asset pipeline wants it (javascript_include_tag "file" to serve file.js). Of course, I would do this via a script but it still seems like a problem someone should have encountered first.
Since neither vendor/assets and public/ folders seem to be a proper location for these files I would like a better option (or a way to make the later options work better).
A solution to keep your files under asset pipeline when they are too big to reasonably be left in one single minimified asset file is to split your assets by categories, compile those categories in different minimified files, and include them in your views when needed.
I do it for an app that contains several "heavy" javascripts components that are located in different area of my app and are not often used.
1- Organize your file structure
In app/assets/javascrips and app/assets/stylesheets create one directory per category we are going to create. Examples:
app/assets/javascrips/common
app/assets/javascrips/admin
app/assets/javascrips/user_account
2- Create your manifests
In app/assets/javascrips and app/assets/stylesheets create one manifest file per category and have them included the related directory
File app/assets/javascrips/common.js
//= require jquery
//= require_tree ./common
File app/assets/javascrips/admin.js
//= require_tree ./admin
File app/assets/javascrips/user_account.js
//= require_tree ./user_account
3- Add your manifests to rails precompile list
You can do it in config/application.rb file, but when it gets big it is preferable to create an initializer file config/initializers/assets.rb
Rails.application.configure do
config.assets.precompile += %w[common.js admin.js user_account.js]
end
4- Include them in your views and layouts, and set-up your javascript libraries.
Import the assets files into layouts and views. It can be a good idea to create several layouts for different area of your application that would be using common assets files. The methods to use are
stylesheet_link_tag 'manifest_file' and javascript_include_tag 'manifest_file'
And keep in mind you may have to tell your javascript plug-ins they need to use the miniminied file when dynamically loading files. For them you can use a configuration .js.erb file. Example:
File app/assets/javascrips/admin/plug-in_config.js.erb
PLUGIN.config('dynamicFileName', '<%= javascript_path('manifest_file') %>');

Managing assets for different areas with Rails

Is it possible to have different assets for different areas of a site in Rails. For example, in my admin area, I'm using bootstrap but this is getting loaded in non admin areas too. I guess it's to do with my folder structure but I've tried moving it and haven't really had any luck.
Anything admin related is where you'd expect a normal controller, view or asset except it's nested within an admin folder. E.g.
App > Assets > Stylesheets > Admin
You can customise the asset pipeline to whatever you require.
described in detail here:
http://guides.rubyonrails.org/asset_pipeline.html#manifest-files-and-directives
also here:
http://railscasts.com/episodes/279-understanding-the-asset-pipeline
Note in your app/assets/javascripts/application.js this little line:
//= require_tree .
which instructs sprocket to load all files in your assets javascript folder tree. Change this this line to limit to specific files.

Is there a "Rails Way" to fold a Twitter Bootstrap theme into a Rails 3 application?

I purchased a nice-looking Twitter Bootstrap them online that is going to spice up my Rails 3.2.8 application. The package contains the following directories:
/css
/img
/js
Of course these files will have relative links to each other in them. Is there a standard way of integrating this type of stuff into the asset pipeline, or is it still a standard practice to put it under public?
You'll want to use the asset pipeline. Everything is moving that direction and it's really not any harder (except when it is). Your files will go in the /app/assets/ directory.
For the css, you should be able to drop it right into app/assets/stylesheets/, just be sure that bootstrap is included first. There are several gems that make it easy to include bootstrap's files. I use bootstrap-sass, but you might also try twitter-bootstrap-rails (depends on if you want sass support or not). With either one, look at the readmes that I linked to as they include some useful details you'll want to know for each gem.
For the javascript, it should be about the same thing. In your application.js file, be sure that bootstrap is include before //= require_tree . in case the theme adds any custom javascript. Both of the gems I listed before also include the javascript files for bootstrap. You can read their documentation to see the details (it's almost exactly the same as normal for both gems).
As far as images are concerned, put them in the app/assets/images/ directory and you'll have to change the stylesheets a bit for it to work. When an image is declared in the stylesheet, like background: url('./images/bg.jpg');, you'll need to use the image_path helper instead, so it would look like background: url(image_path('bg.jpg'));. Notice I just included the name of the image. The asset pipeline will automatically parse this to the correct path for you.
If the theme includes any custom fonts, you'll do the same as images except using the asset_path helper like so in your #font-face declaration:
url(asset-path('museo700.ttf', font));
There are also type-specific helpers you can use, such as font-path, image-path, etc. Either asset-path with a type declared or the type-specific helper will work, just be consistent with which one you use so as not to produce confusion.
You can place custom fonts in a directory something like app/assets/fonts/. The asset pipeline will automatically find them, since they're in the assets directory.

Engine's assets with Rails 3.1

How should one provide assets in an engine in Rails 3.1? Where should they be located and can they be included automatically?
(originally asked by Tomas Celizna)
The paths to the all the engines' assets folders are automatically loaded.
The assets themselves are not loaded by default. This is understandable as the loading is done with require_tree ., which loads all css/js from the current folder (i.e. the main application assets' folder) but doesn't say anything about the engines assets.
The easy solution is to ask the user to require the js/css in application.js/css or wherever else it is needed. As the paths are loaded correctly, the user only need to specify the name of your asset (I'd recommend using the name of your engine). Example:
Appended to main_app/app/assets/javascripts/application.js:
//= require your_engine_name
If you have split your js in different files, your file your_engine_name/app/assets/javascripts/your_engine_name.js could have the following:
//= require_tree .
This will load all js files in your_engine_name/app/assets/javascripts/, as the "." refers to the local folder (in this case the folder of your engine's javascripts).
Note that ActionView::Helpers::AssetTagHelper.register_javascript_expansion appears not to have any effect when config.use_sprockets is set. I hope they'll at least put a warning in that case.
If you have a rake task to install your engine, then you could do the append to application.js.
Another way for the user to include it is to insert <%= javascript_include_tag "your_engine_name" %> in the erb layout.
I don't think there is a way to have it inserted automatically

Resources