conditional loading of stylesheet - ruby-on-rails

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.....

Related

rails overriding/scoping views for multi tenancy app

I'm wondering how I can scope my views. I want to have custom themes depending on the organization, I can use render directly on the show/index actions... and that works, but I would have to override a lot of actions on my application. I would prefer to do it on the controller level and tried doing it with prepend_view_path but it didn't except the variable as undefined.
class EditionsController < ApplicationController
helper_method :current_organization
prepend_view_path "app/views/#{current_organization.slug}/editions" #doesn't work
def show
#edition = Edition.find(params[:edition_id])
#page = #edition.pages.first
render template: "#{current_organization.slug}/editions/show" #works
end
Any ideas?
Also tried: (with same error)
append_view_path(File.join(Rails.root, "app/views/#{current_organization.slug}"))
custom themes depending on the organization
Surely it would make more sense to define custom layouts & CSS rather than entirely different view sets for each company?
--
I would personally do this:
#app/layouts/application.html.erb
<%= stylesheet_link_tag "application", controller_name ... %>
This will give me the ability to style the different pages as per the theme. Obviously a constriction on what you want, but I hope it shows how you could modularize your controllers etc
--
If you wanted to create different "themes" (IE having a completely different view structure per tenant), you'll want to use the prepend_view_path helper, as described here:
#app/controllers/application_controller.rb
Class ApplicationController < ActionController::Base
prepend_view_path("views/#{current_organization.slug}")
end
Try to remove editions in prepend_view_path
prepend_view_path "app/views/#{current_organization.slug}"
Make sure what the way was added. If it doesn't add before_filter

RoR stylesheet layout view link. What does `:media => all` mean

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.

Change layout for Devise controllers

I am using gem devise. Devise extends application controller and adds user managment to rails application.
When I look inside the gem I can see following line
class Devise::SessionsController < ApplicationController
I am trying to change this since I want Devise controller to inherit from my custom controller named AdminController. Reason for this is I have whole web application finished and I do not want admin part of the page to use my application layout, css, js ...
How can I dynamically change base class of controller? Or dynamically tell controller to use admin.html.erb layout instead of application.html.erb layout.
When I say "dynamicly" I mean monkey patch it, thank you.
This solved my problem, if namespace of controller is Devise use admin layout.
class ApplicationController < ActionController::Base
protect_from_forgery
layout :determine_layout
def determine_layout
module_name = self.class.to_s.split("::").first
return (module_name.eql?("Devise") ? "admin" : "application")
end
end
Devise is a rails engine. I think that the best way to make a admin section of you site is to make a rails engine. Or better still use rails_admin or activeadmin. They are both rails engines There is a railscast about rails engines
I don't know the inner works of you app, but if you add
layout "admin"
to your AdminController and add a custom admin layout to the view/layouts folder with
<%= stylesheet_link_tag 'admin' %>
<%= javascript_include_tag "admin"%>
the AdminController views will use the admin stylesheet and javascript
If you just need to change the layout, I think you should be able to do it by re-opening the controller class. At the bottom of your initializers/devise.rb (underneath the config section at the top level, you could write:
Devise::SessionsController.layout :admin
I've not tried this, but in theory it should work since layout is just a class method on ActionController.base.

How can I customize the active admin layout?

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.

Allowing users to choose custom theme in Rails

I want to give my users the ability to choose how their public page is displayed from 5 different layouts. I assume I'll need 5 different css files according to layout and then need to pass that into stylesheet_link_tag
I know only how to do it using if then statements. I don't suppose that is the best way. Any help...also could it be done?
Thanks
You should store the layout that the user has chosen in the session variable (easiest, but lost when the user clears cookies or uses a different computer), or in your database.
Lets say the stylesheets have five names, each corresponding to a color:
blue_stylesheet.css
green_stylesheet.css
red_stylesheet.css
orange_stylesheet.css
white_stylesheet.css
Place these files inside of public/stylesheets.
Store the user's choice of stylesheet into the session[:style] variable like so:
session[:style] = 'green'
This value will persist for as long as the user does not clear their cookies.
Create an application.erb file in your layouts if one does not already exist. The code in this file will be rendered for every template on your site. It should contain a line like <%= yield %>. In this file place the following:
<%=stylesheet_link_tag session[:style]+'_stylesheet'%>
That's it!
Good luck!
First, try to add 'theme' field to user's model (using migrations).
Then add some links in a view (user's settings):
link_to 'Change to green theme', :controller => "user", :action => "set_theme", :id => "green"
Controller:
def set_theme
# don't forget to check, is there a theme with such params
current_user.update_attributes :theme => params[:id]
end
Public profile's controller:
def public_profile
#theme = 'default'
user = User.find(params[:user_id]) # profile's owner
#theme ||= user.theme # overriding default theme to custom one
end
layout:
<%=stylesheet_link_tag #theme %>

Resources