Object.const_get and Rails - disable parent module names

I have the following code to output and instantiate Rails controllers:

def get_controller(route) name = route.requirements[:controller] return if name.nil? if name.match(/\//) controller_name = name.split('/').map(&:camelize).join('::') else controller_name = name.camelize end p controller_name: controller_name controller = Object.const_get("#{controller_name}Controller") p controller: controller controller.new end 

some routes are single names - "users", "friends", "neighbors", "politicians", etc.

other routes are nested, for example, "admin / pets", "admin / shopping_lists", "admin / users", etc.

The code above works (in that it correctly creates and creates an instance of the controller) in most of the cases mentioned, with the exception of one - in this example, "admin / users"

from puts statements, I get the following:

 {:controller_name=>"Admin::Users"} {:controller => UsersController} 

You will notice that the Admin namespace is being disabled. I assume that since this only applies to controllers that use the name in multiple namespaces ( users and admin/users ), it has something using Rails autoload (?). Any idea what causes this?

According to the comment from lx00st, I should also indicate that I have tried various forms of getting these constants, another attempt was as follows:

 sections = name.split('/') sections.map(&:camelize).inject(Object) do |obj, const| const += "Controller" if const == sections.last obj.const_get(const) end 

The same problem was encountered with this approach.

+1
ruby ruby-on-rails
source share
2 answers

This was resolved by a response from apneadiving, which can be found here.

Keep in mind that there are vicious cases in Rails development mode. To get speed, a strict minimum is loaded. Rails then searches for class definitions when necessary.

But this sometimes is not suitable for an example with a long time, when you already said ::User already loaded, and then look for ::Admin::User . Rails will not look for it, it will think that ::User doing the trick.

This can be solved using the require_dependency statements in your code.

Personally, I think this is a mistake, not a feature, but ... the way it is. This solves the problem.

+1
source share

First of all, this code is superfluous:

 if name.match(/\//) controller_name = name.split('/').map(&:camelize).join('::') else controller_name = name.camelize end 

A single line will do just fine with both cases:

 controller_name = name.split('/').map(&:camelize).join('::') 

Then, you probably want to handle namespaces correctly:

 n_k = controller_name.split('::') klazz = n_k.last namespace_object = if n_k.length == 1 Object else Kernel.const_get(n_k[0..-2].join('::')) end controller = namespace_object.const_get("#{klazz}Controller") 

Hope this helps.

+1
source share

All Articles