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.
Related
I'm building a web site with a part that users can browse and administrative panel. How can use different application layouts for different parts of the site? Is it possible?
You can use layout method to render different layout for different controllers.
class MyController < ApplicationController
layout :admin_layout
private
def admin_layout
# Check if logged in, because current_user could be nil.
if logged_in? and current_user.is_able_to('siteadmin')
"admin"
else
"application"
end
end
end
You can use seperate views, for example if your run rails g controller home index you get a home_controller.rb and in the views folder you get a home folder with an index view. In your controller you can put your logic there and present it in the view.
Check this link seems to be good for beginners
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
How could I create and use a new template instead of application.html.erb in a RoR application? What are the setting that I need to change to have another template?
Actually, all controllers will search for same-named layouts by default inside /views/layouts folder with fallback to application.html.erb. For example, UsersController will search for users.html.erb. Anyway, to use other layout add next to your controller:
class UsersController < ApplicationController
layout 'custom'
end
I am using the Rails forem gem and I would like to use a different layout for some of the forum actions. How would I go about doing that?
If it's for some particular actions inside a controller then I would use a decorator for that. Simply put this file in app/decorators/forem/forums_controller_decorator.rb:
Forem::ForumsController.class_eval do
layout "my_special_layout", :only => :show
end
If you want it for all the actions in a specific controller then you should use an intializer:
Rails.application.config.to_prepare do
Forem::ForumsController.layout "my_special_layout"
end
I'm pretty new to Rails and have an issue which I can't quite get my
head around as to the architecturally 'correct' way of doing it.
Problem relates to what I kinda call sub-controllers. The scenario is
this:
I have a series of pages, on which is a panel of some form containing
some information (think the user panel on gitHub top right).
So, in my app, I have controllers that generate the data for the pages
and render out the responses which is fine, but when it comes to this
panel, it seems to me that you would want some sort of controller action
dedicated to generating this panel and it's view.
Question is, how do you go about doing this? How do I render a 'sub
controller' from within a view?
I would put the logic in a helper or a module. (http://api.rubyonrails.org/classes/ActionController/Helpers/ClassMethods.html)
Then render partials where you want these things displayed. (http://api.rubyonrails.org/classes/ActionView/Partials.html)
Like Herman said, if it's logic that you need generated after the controller hands off to the view (ie, the Pages controller generates a page view, but you want a customized panel) then put it in a helper. Or, call a separate method in your Pages controller before handing off to the view. Or, if it's a lot of logic, create a Module and stick it in your /lib folder. So you could have a whole Panel module with methods that generate different parts of your Panel and which are called by your controller. But if you want to call these methods from within the view, then you should use a helper instead.
I dont think a module is what is required here, modules are required for shared behaviour across a small subset of your classes.
What I think is required here is the understanding of the inheritance of ApplicationController and also layouts
so, for example, my layout might look like:
<html>
<head><title>Foo</title></head>
<body>
<%= render :partial => (current_user ? "/shared/user_widget_bar" : "/shared/login_bar") %>
<%= yield %>
</body>
</html>
Any code that i want to use for it would go in my ApplicationController since it would be shared across the majority of my app:
before_filter :generate_user_widget
def generate_user_widget
if current_user
#avatar = ...
#unread_messages = ...
end
end
I understand that it might be cleaner for it to belong in a separate controller BUT honestly, unless the code is huge, it doesn't matter and can even still be put inside a module which is then included by ActionController. However it does need to be inside ApplicationController if you consider the scope of it.
If there are more related pages, say for example, you have a Rails app that manages multiple sites and you want shared behaviour across a particular site, try creating a parent controller which has no actions and only private methods, any controllers that need to have access to those methods can inherit off it. That way you can apply before filters to all controllers which inherit off it, saving you the pain of forgetting to add one in your non-parent controllers.
e.g:
class SiteA::SiteAParentController < ApplicationController
before_filter :generate_user_widget
...
end
class SiteA::ProductController < SiteA::SiteAParentController
def index
...
end
end
well, if you really need to call a controller action from the view, you can use components. They were part of the framework, now they only exist as plugins. One such plugin that seems to be well maintained is here: http://github.com/cainlevy/components/tree/master
from its docs:
== Usage
Note that these examples are very simplistic and would be better implemented using Rails partials.
=== Generator
Running script/generator users details will create a UsersComponent with a "details" view. You might then flesh out
the templates like this:
class UsersComponent < Components::Base
def details(user_or_id)
#user = user_or_id.is_a?(User) ? user_or_id : User.find(user_or_id)
render
end
end
=== From ActionController
class UsersController < ApplicationController
def show
return :text => component("users/detail", params[:id])
end
end
=== From ActionView
<%= component "users/detail", #user %>