A separate assets folder for mobiles devices? - ruby-on-rails

I want to make my rails application mobile-friendly. There're some ways but I'm using the one where it check the user agent and passes the parameters "is_mobile" in a url and serves views from a different folder -- I don't have a different mime type for mobiles, I'm just using a different view folder and I'm fine with that.
In my ApplicationController I call prepend_view_path if a request comes from a mobile devise.
I wonder, what to do with the assets: images, js, css? Should I also create a new folder for mobile for assets -- "my_assets_for_mobile" and prepend it to the path? Something like: prepend_assets_path(....) if mobile_request? Or what?

Yes you can. First step is knowing if the device requested a mobile version.
Second step is to to this: (in your application.html.erb layout)
<% if mobile? %>
<%= stylesheet_link_tag 'application-mobile', media: 'all' %>
<% else %>
<%= stylesheet_link_tag 'application', media: 'all' %>
<% end %>
Then you just have to make application-mobile.css manifest in your assets folder (copy and modify the application.css
In application-mobile.css you can define which assets get loaded for mobile, which ones are shared with the application.css and other stuff like that

You can use Webpack for achieving this, this is a very good tool for manging assets. You can also create page specific assets to be loaded on page. You can decide on the fly which assets to be loaded for the page based on your requirements, like mobile friendly assets or for others.

Related

Multiple layouts in Ruby on Rails

I have a project where each page needs to import an extra css or JS file for only that page. Is it a good practise to use a different layout file for each view? (I don't want my view files to contain references to css/JS files).
I mean i can have a different layout for each view but i don't know if it is the optimal way to do it.
Best strategy:
Don't worry about it and just let your app handle this for you. Minified CSS and JS file delivery isn't really that slow/big and Rails will compile your assets into single files in production.
If you're determined, it is possible (your mileage may vary depending on your Rails version, and usage of Sprockets or Webpacker)
And you'll really want to understand the Rails asset pipeline (for your version of Rails) before you go nerfing these settings.
CSS inclusion/exclusion
You can ignore the asset pipeline and manually choose which CSS files to include, but you'll need to be diligent about doing this everywhere.
In your app/views/layouts/application.html file, you have a line like this inside the <head> tag:
<%= stylesheet_link_tag 'application', media: 'all' ... %>
This is loading application.css, which is a compiled version of app/assets/stylesheets/application.css and will include all CSS from all other files inside app/assets/stylesheets
Depending on your version of Rails, you'll need to turn off asset pre-compilation in either config/initializers/production.rb or config/initializers/assets.rb:
Rails.application.config.assets.precompile = []
Warning: this will turn off ALL asset compilation, including JS. Be sure you have a strategy to re-include JS files (based upon your asset pipeline)
You will now need to implement some logic to handle what CSS is included when. This could be in app/helpers/application_helper.rb. It could use the view helper [controller_name], (https://apidock.com/rails/ActionController/Metal/controller_name/class), for example, to determine which page you are on and fetch the correct CSS file.
Really rough example:
# app/helpers/application_helper.rb
module ApplicationHelper
def css_file_chooser
"/app/assets/stylesheets/#{controller_name}.css"
end
end
Then in your application.html file, you can do something like this:
<head>
<%= stylesheet_link_tag css_file_chooser, media: 'all' ... %>
...
</head>
The catch here is you'd need to have your specific CSS files named according to your controllers. E.g. if controller_name returns 'posts', you'd need to have a file: 'app/assets/stylesheets/posts.css'
If you do have some site-wide CSS that needs to be applied, you'd need to include a second stylesheet_link_tag:
In this case, if you put all your global styles into app/assets/stylesheets/global.css:
<head>
<%= stylesheet_link_tag 'global', media: 'all' ... %>
<%= stylesheet_link_tag css_file_chooser, media: 'all' ... %>
...
</head>
JS inclusion/exclusion
It's a bit dusty, but this article outlines a strategy that only loads a JS function or file if the <body> has certain class tags. I used to use it on my Rails 4 and 5 projects.

Rails - Assets loaded on all pages

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

Rails and Page Specific Javascript

Ok, I realise this question has been asked many times but the answers never seems to address the issue/question I have with this.
I have a js file that I would like to include on specific pages only. There are many responses that suggest that I put files into folders and then in the manifest file reference only those folders - for example this Railscast (at about 06:20) talks about this.
However, I only have one application layout file (and I guess this could be the area I'm lacking in) - therefore this file points to the application.js manifest and therefore I can't see how I can include things conditionally.
It's a bit like this resource too - http://railsapps.github.io/rails-javascript-include-external.html - scroll down to the page-specific scripts sub heading and it repeats what the Railscast suggests. But nothing is mentioned of multiple application layout files.
If anyone can help me clarify what to do in this situation I would be most grateful.
I should perhaps point out that I'm using Rails 4.
You can use content_for in your views to "inject" content into the layout when said view is to be rendered. See: using-the-content-for-method
You'd need to do a few things to make this happen:
Add the placeholder to yield the content in the layout. ex.
<%= yield :js %>
Add the block (to be yielded) to your view. ex:
<%= content_for :js do %>
<%= javascript_include_tag "my_script" %>
<% end %>
If you are using the asset pipeline in production and you want to reference a particular asset like a "my_script.js", in your production.rb or relevant environment config.you will need to precompile it using:
config.assets.precompile=["my_script.js"]
In application.html.erb, use this to add controller specific javascript instead of application specific javascript. Make sure you remove require_tree.
<%= javascript_include_tag params[:controller] %>
Read more on this topic on Rails Guide.

where to put external assets in ruby on rails project?

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.

Rails asset pipleline: compile to multiple stylesheets

Due to a specific setup, I would like to split the compiled stylesheets in two files. This is because (a part of) the CSS is needed for a Java application which can parse the CSS, but it is a bit buggy and can't handle some css-(hack)-syntax. Because I am unable to modify this Java application, I want to feed it only the CSS which it needs and of which I can make sure it is correct.
So, normally the assets pipeline would produce just one '/assets/application-[..].css' file. It would to let it also generate '/assets/custom-[..].css', based on a file selection I make. This still can be pre-compiled.
Is there a way to do this? Although I understand this is not the ideal setup..
To tell rails about additional files you wish to have precompiled, you can add them to the config.assets.precompile setting.
config.assets.precompile += ["other_application.css"]
You only see application.css in your HTML because that's the only file you're including
<%= stylesheet_link_tag "application" %>
If you have some custom.css.scss in your apps/assets/stylesheets directory, it will be compiled just like application.css.
For example, I might have
- _common.css.scss
- application.css.erb.scss
- other_application.css.erb.scss
in app/assets/stylesheets. In the top of the non-partial files I will put
#import "common";
to include _common.css.scss. I can now reference either stylesheet independent of one another in a layout.
<%= stylesheet_link_tag "application" %>
# or
<%= stylesheet_link_tag "other_application" %>

Resources