Trying to dynamically load code to override the widget is the wrong approach to take. Instead, the widget
method should decide which version to display on a request-by-request basis. Before we look at some ways to do that, let's explain why the module overriding doesn't work.
ApplicationController
is loaded when your Rails application starts. This automatically includes the ApplicationHelper
module, which defines the widget
method. The AdminHelper
isn't loaded because of the config.action_controller.include_all_helpers
setting - by setting it to false
Rails will only load a helper with the same name as the controller.
When a regular user calls the widget
method, the string "widget"
is returned. But as soon as an admin visits the site the include_backend_helpers
callback loads your AdminHelper
module, overriding the widget
method. The admin gets the string "admin-widget"
returned - but so does every future visitor to the site! The widget
method isn't differentiating based on user types.
You could solve this by reloading the ApplicationController
after each request, but that takes time and will make performance suck. You might be able to unload the module, but that seems like an approach fraught with difficulty. You could also try reloading the helper on each request:
def include_backend_helpers
if admin_signed_in?
self.class.helper "admin/backend"
else
self.class.helper "user/backend"
end
end
But I'm not sure that would work, and I wouldn't recommend it.
Instead, it seems that it's the widget's job to decide what's appropriate to display. For instance, if this was a navigation component, it should be smart enough to only show admin links. You can still break it out into separate methods:
module ApplicationHelper
def widget
if admin_signed_in?
user_widget
else
admin_widget
end
end
private
def user_widget
"widget"
end
def admin_widget
"admin-widget"
end
end
You can use a similar approach with Rails partials - you could have a _navigation.html.erb
partial that includes either _user_navigation.html.erb
or _admin_navigation.html.erb
based on admin_signed_in?
. Your view includes `<%= render "navigation" %>", and doesn't worry about the internal details.
If you have enough code that the above starts to feel unwieldy, then you should look at Cells for Rails. It's a gem that makes it easier to build encapsulated display components - combinations of controller logic and view code.