Controller specific manifests in rails 4 - ruby-on-rails

Rails 4
How can I include/exclude manifests based on their controllers?
I have application.css - which includes global assets used by all layouts.
In addition, I have a frontend.css and a dashboard.css
I would like application.html.erb to include application.css and frontend.css, but exclude dashboard.css
I would like dashboard.html.erb to include application.css and dashboard.css, but exclude frontend.css
How should I structure my assets, and what should the layout files and manifests look like?

I would do this:
#app/views/layouts/application.html.erb
<%= stylesheet_include_tag "application", media: "all", "data-turbolinks-track" => true %>
<%= stylesheet_include_tag type, media: "all", "data-turbolinks-track" => true %>
#app/helpers/application_helper.rb
def type
controller_name == "dashboard" ? "dashboard" : "frontend"
end
#app/assets/stylesheets/application.css
/* global manifest -- fonts etc */
#app/assets/stylesheets/dashboard.css
/* dashboard specific */
#app/assets/stylesheets/frontend.css
/* frontend specific */
Basically, I would put some logic in the layout, which could be condensed to a helper, to determine which controller / conditions are valid to load up dashboard.css / frontend.css
Hope this helps?

Related

How to properly configure the connection of .css files to .html.erb files if i have 2 controllers. Ruby on Rails

For exemple, i have something contoller_1 with index.html.irb, and i have something controller_2 with index2.html.irb, how to properly connect .css files to this html-documents. I want to connect separate files to index.html.irb (for exemple, index.css) and to index2.html.irb (for exemple, index2.css).
thank you!
You can use all stylesheets with:
<%= stylesheet_link_tag "application", :media => "all" %>
...or you may create a separate directory that will use your external stylesheet
asset::your_external_css::new_sytle
<%= stylesheet_link_tag "application", "your_external_css/new_style" %>
found in (app/views/layouts/application.html.erb)

Capybara RSpec with CSS and JS?

rails (5.1.4)
rspec-rails (3.7.2)
capybara (2.16.1)
I'm trying to create a RSpec Rails 3.7 System spec as in https://relishapp.com/rspec/rspec-rails/v/3-7/docs/system-specs/system-spec .
Here my simple spec:
require 'rails_helper'
RSpec.describe "testing system", type: :system do
it "tests the spec" do
visit root_path
click_link 'Home'
save_and_open_page
end
The problem is that Capybara does render neither CSS content nor JS content after save_and_open_page call (in the browser) - just a plain HTML. The header inside this HTML-file contains some links
<link rel="stylesheet" media="all" href="/assets/application-ea5a1efcc44a908543519edabe00e74132151ebedeef3c1601921690d9162b5e.css" data-turbolinks-track="reload" />
<script src="/assets/application-ff63e43aef379fef744a00f21a8aadf96dc2ae8e612f8e7974b231f946569691.js" data-turbolinks-track="reload"></script>
but they reference some empty files.
Is there some way to fix it?
I tried some recipes, but still no luck. I tried to precompile the assets, to move "capybara.html" into the "public" folder, but no effect.
Modifying stylesheet_link_tag is not a good solution, a much better solution is to specify Capybara.asset_host which will add a <base> tag to any saved pages. Generally this would be set to something like
Capybara.asset_host = "http://localhost:3000/"
which would then load the JS/CSS assets from your dev server which would have access to the test mode compiled assets in the public subdirectory. Note: that none of this means the page will actually be functional since JS requests will still fail, DB records won't exist anymore, etc. Also, since it saves element attributes (not properties) a checkbox you just checked will probably not be checked in the saved page. However it will give you a generally styled page you can inspect the structure of. If all you're looking for is a current image of the page you should be using the save_screenshot/save_and_open_screenshot functionality provided by most of Capybaras drivers instead.
It has to do something with your assets.
Clear cache and run rake assets:clobber and rake assets:precompile
Still no luck, then check if Capybara is configured correctly.
Check app/views/layouts/application.html.erb has the correct Rails tags for stylesheets and javascripts. Something like this:
<!DOCTYPE html>
<html>
<head>
<title>My App</title>
<%= stylesheet_link_tag 'application', media: 'all' %>
<%= javascript_include_tag 'application' %>
On the command line, run:
rake assets:clobber
rake assets:precompile
Ensure that public/assets/ include:
.sprockets-manifest-<xyz>.json
application-<abc>.js
application-<def>.css
Open the .sprockets-manifest... file and you should see that there are application js and css files with filenames that match the actual public/assets/ files. This .sprockets-manifest file controls what actually gets included in the HTML head links and scripts when the Rails tags are replaced.
If this is still not working, ensure that the files are accessible by your user running the test (including the manifest). Occasionally lose the .sprockets-manifest file when copying files and in source control as it can appear to be hidden.
Finally, check your file log/test.log to see if there are any obvious errors being thrown during the tests.
I found a solution. Perhaps it's not the best one, but it works with me. If anybody find a better approach - let me know, please.
Run rake assets:precompile. I didn't even set RAILS_ENV=test.
Modify the stylesheet_link_tag method:
def stylesheet_link_tag2(*sources)
options = sources.extract_options!.stringify_keys
path_options = options.extract!('protocol').symbolize_keys
sources.uniq.map { |source|
tag_options = {
"rel" => "stylesheet",
"media" => "screen",
"href" => path_to_stylesheet(source, path_options)[1..-1]
}.merge!(options)
tag(:link, tag_options)
}.join("\n").html_safe
end
The idea is to turn the rendered link from this:
<link rel="stylesheet" media="all" href="/assets/application-ea5a1efcc44a908543519edabe00e74132151ebedeef3c1601921690d9162b5e.css" data-turbolinks-track="reload" />
to this:
<link rel="stylesheet" media="all" href="assets/application-ea5a1efcc44a908543519edabe00e74132151ebedeef3c1601921690d9162b5e.css" data-turbolinks-track="reload" />
eliminating the leading slash in the href attribute value (since we don't have a server running but just a saved HTML-page).
Replace the code inside the header in \app\views\layouts\application.html.erb to:
<% if Rails.env.test? %>
<%= stylesheet_link_tag2 'application', media: 'all', 'data-turbolinks-track': 'reload' %>
<% else %>
<%= stylesheet_link_tag 'application', media: 'all', 'data-turbolinks-track': 'reload' %>
<% end %>
Write a spec like this:
require 'rails_helper'
RSpec.describe "testing system", type: :system do
it "tests..." do
visit root_path
click_link 'Home'
save_and_open_page Rails.root.join( 'public', 'capybara.html' )
end
end
Add to .gitignore:
/public/capybara.html
Do the same thing with the JS-content.
UPDATE:
If you don't like modifying \app\views\layouts\application.html.erb you can do some monkey patching:
include ActionView::Helpers::AssetTagHelper
alias_method :old_stylesheet_link_tag, :stylesheet_link_tag
def stylesheet_link_tag2(*sources)
options = sources.extract_options!.stringify_keys
path_options = options.extract!('protocol').symbolize_keys
sources.uniq.map { |source|
tag_options = {
"rel" => "stylesheet",
"media" => "screen",
"href" => path_to_stylesheet(source, path_options)[1..-1]
}.merge!(options)
tag(:link, tag_options)
}.join("\n").html_safe
end
def stylesheet_link_tag(*sources)
if Rails.env.test?
stylesheet_link_tag2(*sources)
else
old_stylesheet_link_tag(*sources)
end
end
I usually put such code into app\helpers\application_helper.rb and add include ApplicationHelper into app\controllers\application_controller.rb
UPDATE 2
Setting Capybara.asset_host = "http://localhost:3000/" as #Thomas Walpole advised doesn't work. That's right - how can it work if http://localhost:3000/ is unavailable (AFTER the spec ran)? Of course - when I call save_and_open_page the HTML-file opens with a file://.... address - with no HTTP-server serving it. The attempts to set
Capybara.asset_host = "file://#{Rails.root}/public"
failed - looks like the base HTML-tag supports only http-adresses - not file://... ones. I checked it in Chrome and Firefox.
So my next code proposal is such:
include ActionView::Helpers::AssetTagHelper
alias_method :old_stylesheet_link_tag, :stylesheet_link_tag
def stylesheet_link_tag2(*sources)
options = sources.extract_options!.stringify_keys
path_options = options.extract!('protocol').symbolize_keys
sources.uniq.map { |source|
tag_options = {
"rel" => "stylesheet",
"media" => "screen",
"href" => "file://#{Rails.root}/public" + path_to_stylesheet(source, path_options)
}.merge!(options)
tag(:link, tag_options)
}.join("\n").html_safe
end
def stylesheet_link_tag(*sources)
if Rails.env.test?
stylesheet_link_tag2(*sources)
else
old_stylesheet_link_tag(*sources)
end
end
This eliminates the need to call
save_and_open_page Rails.root.join( 'public', 'capybara.html' )
instead you can simply call
save_and_open_page

Trouble customizing Zurb Foundation with Rails

I am definitely a novice when it comes to SCSS. I need some help.
I am using the Zurb Foundation gem with my Rails 4.2.4 project. I am trying to make some global customizations such as changing the body-bg color. I've gone into the foundation_and_overrides.scss in my assets/stylesheets folder and uncommented
$body-bg: $white;
looking to change it to $steel or some such. When I reload the page, I get
app/views/layouts/application.html.erb where line #7 raised:
Undefined variable: "$white".
application.html.erb starts out:
<!DOCTYPE html>
<html>
<head>
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title><%= content_for?(:title) ? yield(:title) : "foodian" %></title>
<meta name="description" content="<%= content_for?(:description) ? yield(:description) : "Foodian" %>">
<%= stylesheet_link_tag "application" %>
<%= stylesheet_link_tag 'application', media: 'all', 'data-turbolinks-track' => true %>
<%# Modernizr is required for Zurb Foundation %>
<%= javascript_include_tag 'vendor/modernizr' %>
<%= javascript_include_tag 'application', 'data-turbolinks-track' => true %>
<%= csrf_meta_tags %>
I'm sure there is something simple I am overlooking. But I can't find any "for dummies" examples of what to do. Please help.
application.css.scss
/*
* This is a manifest file that'll be compiled into application.css, which will include all the files
* listed below.
*
* Any CSS and SCSS file within this directory, lib/assets/stylesheets, vendor/assets/stylesheets,
* or vendor/assets/stylesheets of plugins, if any, can be referenced here using a relative path.
*
* You're free to add application-wide styles to this file and they'll appear at the bottom of the
* compiled file so the styles you add here take precedence over styles defined in any styles
* defined in the other CSS/SCSS files in this directory. It is generally better to create a new
* file per style scope.
*
*= require_tree .
*= require_self
*/
/*= require foundation */
#import "foundation_and_overrides";
The way I had this working is to add the following line to app/assets/stylesheets/application.scss, and to add this line:
#import "foundation_and_overrides";
You can also remove any *= require foundation from the same file, as foundation_and_overrides already imports the required files.
I am not sure it is the best way, but it works with Foundation 5 (I have not tried Foundation 6 yet).

How can I create 'conditional assets' for feature switches in rails when using the asset pipeline?

I am implementing 'feature switches' so thaty admins can turn new features on and off using an admin web interface.
I'm able to easily do this in views with such such as
- if FeatureSwitch.where(name: 'display_demo_feature_switch_image', status: 'on').count > 0
# in reality would refactor that query to the controller/model. put here for clarity.
%br
%br
%div{class: "onoffswitch"}
%input{type: "checkbox", name: "onoffswitch", class: "onoffswitch-checkbox", id: "myonoffswitch"}
%label{class: "onoffswitch-label", for: "myonoffswitch"}
%span{class: "onoffswitch-inner"}
%span{class: "onoffswitch-switch"}
But how can I do this in views when I am using the asset pipeline and make the assets be 'conditionally' included ?
So if I have a css asset manifest (app/assets/stylesheets/application.css) with:
/*
*= require_self
*= require main
*= require default
*= require on_off_switch
*= require jquery-ui-1.8.22.custom.css
*/
How can I make the require on_off_switch "conditional", depending on a true/false return from
FeatureSwitch
.where(name: 'display_demo_feature_switch_image', status: 'on').count > 0
I tried renaming application.css to application.css.erb and using
<% if 'abc' == 'def' %> # While developing/testing
*= require on_off_switch
<% end %>
but the assets always gets includes despite the fact that 'abc' == 'def' is false...
One possible solution could be creating two manifests, for example say on.css and off.css
In your controller add a before_filter with:
def my_before_filter_name
#count = FeatureSwitch.where(name: 'display_demo_feature_switch_image', status: 'on').count
end
BTW, avoid using active record in your views.
In your layout:
- if #count > 0
= stylesheet_link_tag 'on.css'
- else
= stylesheet_link_tag 'off.css'
Note that you may need to test if #count exists.
If this solutions is not the best option for you case, you can use a content_for. In your layout yield :on_off and in your view add a content_for :on_off and test for #count to stylesheet_link_tag 'on_off_switch' (more details in rails documentation)
The solution seemed to be to just top put the conditional in
app/views/layout/application.html.haml # (I use haml instead of erb)
i.e.
= stylesheet_link_tag 'application'
- if FeatureSwitch.where(name: 'display_demo_feature_switch_image', status: 'on').count > 0
= stylesheet_link_tag 'on_off_switch'
but although that worked in development it didn't wortk in production and the stylesheet wouldn't be included.

Include all javascript files from application except a specific folder in Rails 3.2.11

I would like to exclude a specific folder from assets/javascripts in my application.html.haml
The folder that I do not want to be included in my layout is mobile folder
Here's my layout:
%html(lang="en")
%head
%meta(charset="utf-8")
%meta(http-equiv="X-UA-Compatible" content="IE=Edge,chrome=1")
%meta(name="viewport" content="width=device-width, initial-scale=1.0")
%title= content_for?(:title) ? yield(:title) : #user.name ? 'Niche | ' + #user.name : 'Niche'
= csrf_meta_tags
= analytics_init if Rails.env.production?
/ Le HTML5 shim, for IE6-8 support of HTML elements
/[if lt IE 9]
= javascript_include_tag "//cdnjs.cloudflare.com/ajax/libs/html5shiv/3.6.1/html5shiv.js"
= stylesheet_link_tag "application", :media => "all"
%body#profile
%section.persist-area
%header.global.profile
%div.container
%a.brand.pull-left{ :href => root_path }
.logo-niche
%nav.pull-right
= render 'layouts/menu'
.container-fluid#main
= yield :profile
/
Javascripts
\==================================================
/ Placed at the end of the document so the pages load faster
= javascript_include_tag "application"
= yield :javascript
In this snippet, I am getting all JS:
= javascript_include_tag "application"
But I want to get all JS except the folder named mobile
I tried the following workaround but did not work:
= javascript_include_tag "application", except: "mobile"
Sorry that was just a wild guess. There's no javascript_exclude_tag too as per the docs.
Any ideas? Thanks.
PS: I have a different layout for mobile, so that's why I really want to exclude that folder in desktop view. It's conflicting a lot of conflicts in my desktop view.
Change in application.js
//= require_tree
to
//= require_directory .
or
//= require_tree ./useful
So that, app/assets/javascripts/* files will be included and app/assets/javascripts/mobile/* wont be included.

Resources