How do you find the namespace/module name programmatically in Ruby on Rails?
-
02-07-2019 - |
Question
How do I find the name of the namespace or module 'Foo' in the filter below?
class ApplicationController < ActionController::Base
def get_module_name
@module_name = ???
end
end
class Foo::BarController < ApplicationController
before_filter :get_module_name
end
Solution
None of these solutions consider a constant with multiple parent modules. For instance:
A::B::C
As of Rails 3.2.x you can simply:
"A::B::C".deconstantize #=> "A::B"
As of Rails 3.1.x you can:
constant_name = "A::B::C"
constant_name.gsub( "::#{constant_name.demodulize}", '' )
This is because #demodulize is the opposite of #deconstantize:
"A::B::C".demodulize #=> "C"
If you really need to do this manually, try this:
constant_name = "A::B::C"
constant_name.split( '::' )[0,constant_name.split( '::' ).length-1]
OTHER TIPS
This should do it:
def get_module_name
@module_name = self.class.to_s.split("::").first
end
For the simple case, You can use :
self.class.parent
This would work if the controller did have a module name, but would return the controller name if it did not.
class ApplicationController < ActionController::Base
def get_module_name
@module_name = self.class.name.split("::").first
end
end
However, if we change this up a bit to:
class ApplicatioNController < ActionController::Base
def get_module_name
my_class_name = self.class.name
if my_class_name.index("::").nil? then
@module_name = nil
else
@module_name = my_class_name.split("::").first
end
end
end
You can determine if the class has a module name or not and return something else other than the class name that you can test for.
I know this is an old thread, but I just came across the need to have separate navigation depending on the namespace of the controller. The solution I came up with was this in my application layout:
<%= render "#{controller.class.name[/^(\w*)::\w*$/, 1].try(:downcase)}/nav" %>
Which looks a bit complicated but basically does the following - it takes the controller class name, which would be for example "People" for a non-namespaced controller, and "Admin::Users" for a namespaced one. Using the [] string method with a regular expression that returns anything before two colons, or nil if there's nothing. It then changes that to lower case (the "try" is there in case there is no namespace and nil is returned). This then leaves us with either the namespace or nil. Then it simply renders the partial with or without the namespace, for example no namespace:
app/views/_nav.html.erb
or in the admin namespace:
app/views/admin/_nav.html.erb
Of course these partials have to exist for each namespace otherwise an error occurs. Now the navigation for each namespace will appear for every controller without having to change any controller or view.
my_class.name.underscore.split('/').slice(0..-2)
or
my_class.name.split('::').slice(0..-2)
I don't think there is a cleaner way, and I've seen this somewhere else
class ApplicationController < ActionController::Base
def get_module_name
@module_name = self.class.name.split("::").first
end
end
I recommend gsub
instead of split
. It's more effective that split
given that you don't need any other module name.
class ApplicationController < ActionController::Base
def get_module_name
@module_name = self.class.to_s.gsub(/::.*/, '')
end
end
With many sub-modules:
module ApplicationHelper
def namespace
controller.class.name.gsub(/(::)?\w+Controller$/, '')
end
end
Example: Foo::Bar::BazController
=> Foo::Bar