I have:
<&= stylesheet_link_tag "application", :media => "all" %>
but I am adding a (completely) alternative layout for some of the views in my application, with separate stylesheets. I would like to link the existing layout to only some of the stylesheets, and add others. What do I need to change here?
for this you can create new file in views/layout as similar to your application.html.erb
for example i am creating home.html.erb.Link your all stylesheets and js files in that and finally just add that layout name in your required controller as layout 'home'
You can use separate manifest file and include those manifest file
This answer will help you how to do this
It specifies that your application.css should be loaded when the page is viewed in all media types. It's a CSS property, not a Rails property.
See http://www.w3.org/TR/CSS2/media.html#media-sheets for more details.
You can add a separate layout for whole controller or for specific actions
For example:
in your controller:
layout :resolve_layout
#controller code
...
def resolve_layout
case action_name
when "new", "create", "wait_conformation"
"customer_layout"
else
"producer_layout"
end
end
Here customer_layout & producer_layout are layout files.
Related
Rails 5.1
I mostly work on backend issues, but I am trying to learn more about front end stuff, and I am a little confused about how styles are handled in Rails (I read through a bunch of answers on stackolverflow, but that did not help narrow it down for me).
I have two different views
views/user/login.html.slim
views/user/new.html.slim
I would like to apply different body styles to each view. When the application was generated, Rails added:
assets/stylesheets/users.css.scss
Would I need to add a folder, called users and inside it, have different stylesheets? something like this:
assets/stylesheets/users/login.css.scss
would have in it:
body {
padding-top: 40px;
}
and
assets/stylesheets/users/new.css.scss
would have in it:
body {
padding-top: 80px;
}
Then, in
stylesheets/application.css.scss
I would add:
*= require_self
*= require_tree .
The styles and javascripts are loaded from your layout. Out of the box it looks like this:
app/views/layouts/application.html.erb
<%= stylesheet_link_tag 'application', media: 'all' %>
<%= javascript_include_tag 'application' %>
If you only want to include particular css files in a particular view, you would need to:
Create a layout for your particular view.
Include the appropriate styles and javascripts in the layout.
Specify the particular layout in your controller.
Here is some more information on layouts, but lets go through it for your login example.
app/controllers/sessions/create
class SessionsController < ApplicationController
layout 'login', only: [:new]
# you could also call the layout "sessions.html.erb" and it will be
# loaded automagically
If you want to use a different layout for different actions in the same controller, you can add other layout methods and specify the actions they apply to with the only action.
Then the layout
app/views/layouts/login.html.erb
...
<%= stylesheet_link_tag 'login', media: 'all' %>
...
And finally your stylesheet
app/assets/stylesheets/login.scss
#import "file_you_want";
If you require_tree . it will load all styles in the stylesheets directory which I don't think is what you are after.
I am using a specific bootstrap 4 template for my application. This template (cover.css) is specific to the homepage as all the others pages will use a different style.
How can I use cover.css only for the index action?
In my application.css I added #import "cover" can I have this only applied to the index action?
I tried creating two layouts instead: application.html.erb to use it for the application, and a second layout home.html.erb just for the home page. How can I associate cover.css for only the index action and have my dashboard layout and css for the rest of the application?
I am using rails 5 and bootstrap 4 alpha.
There are a few ways to accomplish this.
You can create a layout which includes the cover.css asset, and then only apply the layout for the index action as described here Rails layouts per action?
class MyController < ApplicationController
layout :resolve_layout
# ...
private
def resolve_layout
case action_name
when "new", "create"
"some_layout"
when "index"
"other_layout"
else
"application"
end
end
end
Another option would be to use a single layout and scope your styles.
In views/layouts/application.html.erb Set classes on the body tag like this
<body class="<%= controller_name %> <%= action_name %>">
When rendered it will output
<body class="home index">
Then in your cover.css scope your styles to the .home.index selector
body.home.index h1{
/* this style is only applied on the home/index page */
}
Something like this will work.
<%= stylesheet_link_tag "application", :media => "all" %>
<%= stylesheet_link_tag params[:controller] %>
See the 3rd answer here: How do I use Controller specific stylesheets in Rails 3.2.1?
There is config.assets.compile=true parameter which enables so called "live compilation".
I need Rails to compile one specific asset (sample.css.scss.erb) on each request in live mode but the rest of assets should be still precompiled.
How can I achieve this?
Option 1 - put sample.css.scss.erb in a path different from config.assets.manifest (default="public/assets") and add it with javascript_include_tag
Option 2 - Remove it from the config.assets.precompile
config.assets.precompile -= %w( sample.css.scss.erb )
Make sure you clean then precompile to test it.
I did not test either option, please let us know if any works for you.
Live compilation for file is required when css is preprocessed by .css.erb file.
It means dynamically compiling css.
For example : allowing users to set the colors and would like to conditionally use "live compilation"
In that case i will suggest dynamically rendering /users/:id/styles.css.erb instead of live compilation.
Reason there might be millions of users and in production environment using Ec2 instance will cost you more. That's why i will suggest below solution:
First define your custom action on the UsersController:
# config/routes.rb
match '/users/:id/styles' => 'users#styles', :as => :user_styles
Link to the "stylesheet" in your layout:
# app/views/layouts/application.html.erb
= stylesheet_link_tag 'application', user_styles_path(current_user, :format => 'css')
Define the action in your controller. You could do whatever you want to retrieve the user's preferences here:
# app/controllers/users_controller.rb
class UsersController < ApplicationController
def styles
#colors = User.find(params[:id]).colors
end
end
That action will automatically render this view:
# app/views/users/styles.css.scss.erb
$background-color: <%= #colors[:background] %>;
body {
background-color: $background-color;
}
More ideas and suggetions are most welcome.
I have a site with clients. Every client can have it's own theme and when a user of a certain client is logged in, the company theme must be loaded. In the application.css.scss I have a line like this for every company:
#import "_theme_x.css.scss";
#import "_theme_y.css.scss";
#import "_theme_z.css.scss";
How can I load only e.g. theme_x when a user of company x is logged in and not load theme_y and theme_z? Or is there a better way of doing this? Thanks!
If themes are large, you might want to separate them from the application.css and load them conditionally in your layout. For example, if you have a helper theme_stylesheet in application_helper which returns the name of the theme the client is using:
# application.html.erb
<%= stylesheet_link_tag 'application', theme_stylesheet %>
If they are small, I like namespacing. Leave your application.css as-is, but modify the themes to use a top-level rule on the body. Place a tag on the body to select the theme. The beauty of this is you can dynamically change the theme.
<body class="theme-<%= theme_stylesheet %>">
...
</body>
_theme_x.css.scss
body.theme-x {
...
}
you can do it in this manner like you can check first whose client is login and apply some
layout for him and include diffrent css files for diffrent layout.
Like i do
first i make method in application helper but i can implement layout according user roles you
can do it according clients.
def choose_layout
if is_admin?(current_user) or is_super_admin?(current_user)
'admin'
else
'application'
end
And in controller call it in before filter than layout will be implement according to user
roles
class AdministratorController < ApplicationController
include ApplicationHelper
layout :choose_layout
def index
#user = User.new
#current_user = current_user
end
end
hope you could get the idea.....
I need to customize the active admin layout, but how can I do it?
The active admin layout is not actually defined as a layout file, but is generated programatically. Placing a custom layout in the layout directory will therefore not actually override the default layout.
You can, however, monkey-patch or duck-punch the active admin layout methods inside your application.
The following will add an ie-specific stylesheet to the header:
module ActiveAdmin
module Views
module Pages
class Base < Arbre::HTML::Document
alias_method :original_build_active_admin_head, :build_active_admin_head unless method_defined?(:original_build_active_admin_head)
def build_active_admin_head
within #head do
meta :"http-equiv" => "Content-type", :content => "text/html; charset=utf-8"
insert_tag Arbre::HTML::Title, [title, active_admin_application.site_title].join(" | ")
active_admin_application.stylesheets.each do |path|
link :href => stylesheet_path(path), :media => "screen", :rel => "stylesheet", :type => "text/css"
end
active_admin_application.javascripts.each do |path|
script :src => javascript_path(path), :type => "text/javascript"
end
text_node csrf_meta_tag
text_node "<!--[if lt IE 7]>
<link rel=\"stylesheet\" type=\"text/css\" media=\"all\" href=\"admin_ie7.css\ />
<![endif] -->".html_safe
end
end
end
end
end
end
Clearly an ugly solution.
When a view is defined in a gem AND in the rails app, the one defined in the Rails app is served. It's a logic priority.
So if you need to override all or some active admin views, you'll have to copy these in your app and change them as you desire.
Maybe ActiveAdmin does provide a nicer way to do this by now? I don't know.
However here would be an example for a bit cleaner patch for that situation, in my example to add the webpacker gems javascript_pack_tag to my admin area.
module MyApp
module ActiveAdmin
module Views
module Pages
module BaseExtension
def build_active_admin_head
super
within #head do
text_node(javascript_pack_tag('application'))
end
end
end
end
end
end
end
class ActiveAdmin::Views::Pages::Base < Arbre::HTML::Document
prepend MyApp::ActiveAdmin::Views::Pages::BaseExtension
end
(Using rails 5.1.4) I tried two solutions here that involved messing with the active_admin library, and they did not work for me at all. I found my solution in config/initializers/active_admin.rb. I am adding a small amount of bootstrap styling to the default layout. As far as linking to stylesheets, javascripts, etc., it was as simple as adding this to my active_admin.rb, as per the comments therein:
# == Register Stylesheets & Javascripts
#
# We recommend using the built in Active Admin layout and loading
# up your own stylesheets / javascripts to customize the look
# and feel.
#
# To load a stylesheet:
# config.register_stylesheet 'my_stylesheet.css'
config.register_stylesheet 'https://stackpath.bootstrapcdn.com/bootstrap/4.5.0/css/bootstrap.min.css', { integrity: 'sha384-9aIt2nRpC12Uk9gS9baDl411NQApFmC26EwAOH8WgZl5MYYxFfc+NcPb1dKGj7Sk', crossorigin: 'anonymous' }
As far as editing that generated layout, I have yet to figure it out, but it could at least be done indirectly via JavaScript and the inclusion of that javascipt in this file via
config.register_javascript 'active_admin_view_tweaks.js', { defer: true }
I am going to be editing class attributes to make my pages responsive with bootstrap, so I might follow something like this geeksforgeeks article to edit the pages with JavaScript after they've loaded.
I don't know if there is a way to edit the generated layout more directly, but this should work for some cases.
You can override the active admin page layout by putting the following code in your config/intializers/active_admin.rb file:
module AdminPageLayoutOverride
def build_page(*args)
within super do
render "shared/your_custom_view_partial"
end
end
end
ActiveAdmin::Views::Pages::Base.send :prepend, AdminPageLayoutOverride
In the above example, I have a custom view file at app/views/shared/_your_custom_view_partial.html.erb location and I am injecting that in all of my active admin pages by the above code.