Sean Hill
Sean Hill

Reputation: 15056

Inherit from Variable Instead of Constant

I am currently writing a Rails engine, and I wanted to make its ApplicationController descend from the controller specified in the engine's config.

For example, I have in lib/my_engine.rb the following:

module MyEngine
  mattr_accessor :authenticated_controller

  class << self
    def authenticated_controller
      @@authenticated_controller.constantize
    end  
  end
end

In app/controllers/my_engine/application_controller.rb, I have:

class MyEngine::ApplicationController < MyEngine.authenticated_controller

  #some code

end

And in my app's initializer, I set MyEngine.authenticated_controller = 'AuthenticatedController'.

This allows me to keep my engine mostly ignorant of the authentication engine, as now all my engine requires is some controller, AuthenticatedController in this case, to provide a method with current_user. I used this blog post for inspiration.

It all seems to work just fine, but I am using RubyMine to develop, and it complains about using a variable instead of a constant in the class definition. It raises the question of whether this is a good idea or not.

So, is this approach okay? Are there some gotchas that I am not seeing? And are there any alternatives to this method?

Upvotes: 1

Views: 144

Answers (2)

dbenhur
dbenhur

Reputation: 20408

As Andrew points out this is fine in Ruby, and the warning is a problem with RubyMine. One possible approach to work-around the warning and still get the same ruby semantics is to use Class::new instead of the class keyword to define your class:

MyEngine::ApplicationController = Class.new(MyEngine.authenticated_controller) do
  #some code
end

Upvotes: 0

Andrew Marshall
Andrew Marshall

Reputation: 96934

This is completely okay—so long as the variable contains a Class instance when this code runs (which would give a TypeError: “superclass must be a Class”).

Ruby only gives this error when you have a non-constant named class/module, e.g.:

class c; end
module m; end

as opposed to

class C; end
module M; end

So either you have this issue elsewhere (unlikely if everything is working as this is an error, not a warning), or RubyMine is incorrectly giving you the error for some reason. Ruby gives no warnings for what you have.

Upvotes: 1

Related Questions