Rails can't find my classes after a while - ruby-on-rails

I have a custom module with a class in Rails. I put this in my autoload inside the application.rb
config.autoload_paths << "#{Rails.root}/classes"
The module has a reference to a file in a deeper folder:
a.rb
require_relative './b/b.rb'
module A
def self.abc content
return A::B.new
end
end
B has nothing fancy:
b.rb
module A
class B
def initialize
end
end
end
What's happening right now is that in the beginning this works perfectly, but after some requests, or a certain amount of time, it stops working and I get an: uninitialized constant A::B error.
Any ideas? The fact that it works in the beginning is confusing me. Thanks in advance.

Related

Rails: controller cannot recognize class from module/namespace - uninitialized constant

I've created directory for API logic: app/api/EtherumAPI/V1 and put there following code:
module EtherumAPI
module V1
class Request
class << self
def trancation
end
end
end
end
end
Registered in my application.rb:
config.autoload_paths << "#{Rails.root}/app/api"
config.eager_load_paths << "#{Rails.root}/app/api"
And try to call it inside my controller:
def index
#test = EtherumAPI::V1::Request
#test.trancation
end
But I got this error:
uninitialized constant HomeController::EtherumAPI
I tried also something like "include EtherumAPI::V1" but it didn't succeed as well. How can I fix it and be able to call methods from Request class?
First off you can get rid of:
config.autoload_paths << "#{Rails.root}/app/api"
config.eager_load_paths << "#{Rails.root}/app/api"
All the subdirectories of app are by default auto-load paths. Occasionally the auto-loader gets "stuck" and will not pick up newly added directories. You can usually fix that by restarting the rails server and spring ($ spring stop).
There are two issues at play here. The first is inflection. Rails inflects file names from classes by camelizing the class name. Unfortunately this does not work automatically for acronyms as ABC -> a_b_c.rb.
So for the autoloader to look for EtherumAPI in etherum_api.rb you need to add an inflection:
# config/initializers/inflections.rb
ActiveSupport::Inflector.inflections(:en) do |inflect|
inflect.acronym 'EtherumAPI'
end
The second issue is that the module names must match the actual path to the file.
# app/api/etherum_api/v1/request.rb
module EtherumAPI
module V1
class Request
class << self
def trancation
end
end
end
end
end

Accessing helpers and models from rails engine initializer

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?
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
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).
In my engine.rb I do
require_relative '../../app/models/my_engine/option'
maybe this will help, but it is not a nice solution.

Rails autoloading example

I am newbie to Ruby on Rails and I broken my head at Rails autoloading mechanisms.
I have code like that in my /app/helpers/posts_helper.rb :
module PostsHelper
def markdown_render(data)
Utils::Markdown.render data
end
end
And I have /app/utils/markdown.rb with something like:
module Utils
class Markdown
class << self
def render(data)
# render some dataz
end
end
end
end
According to http://guides.rubyonrails.org/autoloading_and_reloading_constants.html, Utils::Markdown will be loaded from /app/utils/markdown.rb, but instead I recieve:
ActionView::Template::Error:
uninitialized constant PostsHelper::Utils
I understand that the problem lies in referencing Utils from helper module, but I have zero ideas how to properly make that reference.
Please, help me before my head crashes! =-)
Try:
module PostsHelper
def markdown_render(data)
::Utils::Markdown.render data
end
end
that is, put a double-colon in front of Utils::Markdown. It basically means "look in the root namespace," rather than "look within the namespace I'm currently in".
In markdown.rb, just define Markdown as a top level class (i.e. not in any namespaces).
Okay, I sorta figured it out.
The app/some_name path is "chewed" from module/class finding, so Rails do not expect to find in app/some_name/some_class.rb SomeName::SomeClass, it simply expect to find SomeClass.
I restructured the file ierarchy, so now it is: app/modules/utils/my_markdown.rb, and it correctly autoloads Utils::MyMarkdown from my_markdown.rb =-)

Rails mistakenly nesting called namespace into caller namespace

Bar calls Foo and Rails thinks that Foo must be within the Bar namespace
module Foo
class Lofatook
def oops
puts 'buckets of fun'
end
end
end
module Bar
class Thedoor
def theyhaveacavetroll
Foo::Lofatook.new.oops
end
end
end
Bar::Thedoor.new.theyhaveacavetroll
This works fine as raw ruby. But when I put Foo in lib/foo/lofatook.rb and Bar in app/models/bar/thedoor.rb it throws this error:
uninitialized constant Bar::Foo
We are using the golden lib loading hammer of
config.autoload_paths += Dir["#{config.root}/lib/"]
config.autoload_paths += Dir["#{config.root}/lib/**/"]
with all its glorious drawbacks.
But this should not mean it mistakenly assumes Foo must be part of Bar?
Problem was its not enough to have
module Foo
class Lofatook
end
end
in lib/foo/lofatook.rb. You must also have lib/foo.rb
module Foo
end
Thanks to #ma_il, using ::Foo::Lofatook raised the error uninitialized constant Foo which pointed me in the right direction

Uninitialized Constant in Rails Controller

I have the following in my controller:
class SurveysController < ApplicationController
def index
survey_provider = FluidSurveysProviders::SurveyProvider.new
contact_lists = survey_provider.get_lists()
#survey = Survey.new(contact_lists)
end
And I'm receiving this error:
NameError in SurveysController#index
uninitialized constant SurveysController::FluidSurveysProviders
Excuse my Rails noobiness, I'm sure I'm leaving out something important here. But it seems to me that I am trying to "initialize" the constant with this line:
survey_provider = FluidSurveysProviders::SurveyProvider.new
But that's the same line that's throwing an error because it's not initialized. Where should I be "initializing" the Provider?
Once you require fluid_surveys_providers (or similar) then do this:
include FluidSurveysProviders
Make sure SurveyProvider is wrapped with module FluidSurveysProviders. It may look like this
module FluidSurveysProviders
class SurveyProvider
...
end
end
if its an ActiveRecord object try this
class FluidSurveysProviders::SurveyProvider < ActiveRecord::Base
...
end
The SurveyProvider was not loaded correctly.
For a quick fix, move the class file into app directory, e.g. app/lib/survey_provider.rb. Then all code inside app will be auto-loaded by Rails.
Or make sure the path to class SurveyProvider is included in the autoload_path of Rails. In config/application.rb
config.autoload_paths += %W(#{config.root}/lib) # where lib is directory to survery_provider
If you use Rails 5, be careful that autoload is disabled in production environment. Check this link for more info.

Resources