0
votes

I'm trying to make a Ruby on Rails engine, and I want the initializer to be able to have access to the helpers and models.
I'll write below an example, part of the code, and the error that I have. It may not be the recommended way, because I can see that in some cases I'm repeating myself, but it's the first engine I make.

file lib/my_engine/engine.rb

module MyEngine
  require 'my_engine/functions'

  class Engine < ::Rails::Engine
    isolate_namespace MyEngine
    config.autoload_paths += %W( #{config.root}/lib )
  end

  class GlobalVars
    attr_accessor :foo
    def initialize
      @foo = MyEngine::Functions.new
    end
  end

  class << self
    mattr_accessor :GLOBAL
    mattr_accessor :USER_CONFIG

    self.GLOBAL = MyEngine::GlobalVars.new
    # add default values of more config vars here
    self.USER_CONFIG = 'default config'
  end

  def self.setup(&block)
    yield self
  end

end 

file lib/my_engine/functions.rb

module MyEngine
  require '../../app/helpers/my_engine/options_helper'

  class Functions
    include MyEngine::OptionsHelper

    attr_accessor :some_link

    def initialize
      @some_link = get_option('dummy')
    end
  end
end

There is also a controller named OptionsController in app/controllers/my_engine, and OptionsHelper in app/helpers/my_engine/options_helper.rb:

module MyEngine
  module OptionsHelper
    def get_option(name)
      MyEngine::Option.new
    end
  end
end 

When I try to run the dummy application, this error occurs:

/app/helpers/my_engine/options_helper.rb:4:in `get_option': uninitialized constant MyEngine::Option (NameError)

If I change to just Option.new, I have this error:

/app/helpers/my_engine/options_helper.rb:4:in `get_option': uninitialized constant MyEngine::OptionsHelper::Option (NameError)

For ::MyEngine::Option.new, I have:

/app/helpers/my_engine/options_helper.rb:4:in `get_option': uninitialized constant MyEngine::Option (NameError)

For ::Option.new, I have:

/app/helpers/my_engine/options_helper.rb:4:in `get_option': uninitialized constant Option (NameError)

The dummy application has nothing in it. All helpers and models defined above are in the engine.

Before this, I had other errors because it couldn't access the helper, or the Functions class. I had to add require and include to make it work even if they are placed in the same directory. Also, to work, I had to move GlobalVars from its own file inside engine.rb.

Can somebody show me what I'm doing wrong?

3
There is a lot less messy way to do module configuration. If you then want to be able to do MyEngine.foo instead of MyEngine.configuration.foo then just use delegation. - max
Can you show how and where MyEngine::Option is defined? I am guessing rails is unable to guess the correct path to autoload it? - nathanvda
@nathanvda, it is in app/models/my_engine/ - True Soft

3 Answers

1
votes

After I used required for every class, I ended with ActiveRecord::ConnectionNotEstablished, and it seems that not everything is loaded and available at that point when the GLOBAL object is created.

So I moved the code that was using the models in a separate init method. Then, I added an after initialize event:

  config.after_initialize do
    MyEngine.GLOBAL.init
  end
0
votes

I see a possible problem: because you are inside module MyEngine it might be possible that actually rails is looking for MyEngine::MyEngine::Option, so I see two approaches:

  • just write Option: this will look for MyEngine::Option
  • write ::MyEngine::Option this will look in the global namespace and find MyEngine::Option

Secondly, if that does not help, even though your path seems correct, but you can always explicitly require "my_engine/option" at the top of the file. I am not entirely sure the autoloading in an engine works in quite the same way, and I tend to, in my engine file, require almost everything (to make sure it works).

0
votes

In my engine.rb I do

require_relative '../../app/models/my_engine/option'

maybe this will help, but it is not a nice solution.