Rails lib includes - ruby-on-rails

I have a puzzling issue regarding modules defined in the lib dir
I have two files
#lib/authentication.rb
module Authentication
end
#lib/test_module.rb
module TestModule
end
In my application controller I have
class ApplicationController < ActionController::Base
include Authentication
include TestModule
end
The Authentication Module loads properly but the TestModule does not
I get "uninitialized constant ApplicationController::TestModule"
I am stumped... anyone?
EDIT: Does anyone know where I could look to debug this?

As of Rails 3, make sure to add the lib directory to config.autoload_paths in config/application.rb, so that the file containing your module is read and the module is loaded.
config.autoload_paths += %W(#{config.root}/lib)
Look here for more info on this and loading subdirectories.
Also, supposedly "you shouldn't use require within a rails app, because it prevents ActiveSupport::Dependencies from [un]loading that code properly".

Adding require 'lib/test_module' at the top of your ApplicationController file might help

Related

rails: autoload files inside engine's lib directory

I am working on this rails application with an engine which is sort of sub application adding some more routes to my existing application.
The concept is so powerful, thanks to rails.
But I am facing this weird challenge to autoload file changes inside my engines lib directory in development mode. Every time I make a change inside app directory of engine be it model or controller , it works flawlessly, but no changes to any files under lib directory get's picked up. Is there a way I can do this ? Thanks for your help.
According to Rails::Engine docs you can autoload paths like-
class MyEngine < Rails::Engine
# Add a load path for this specific Engine
config.autoload_paths << File.expand_path("../lib/some/path", __FILE__)
initializer "my_engine.add_middleware" do |app|
app.middleware.use MyEngine::Middleware
end
end
If you don't want to autoload, you can directly require the file in your class with the require statement-
require 'my_engine/my_object'
class MyModel < AR::Base
...
end
This will work because your Engine is already loaded in your app, so you can access libs inside of it.
Put the following code in your config/application.rb
config.eager_load_paths += ["#{Rails.root}/lib"]
If you want this only in development mode use the following
config.eager_load_paths += ["#{Rails.root}/lib"] if Rails.env.development?

Rails engine concerns autoload paths

I have some rails engine 'Core', and I have:
# core/app/models/core/concerns/user_helper.rb
module Core
module UserHelper
extend ActiveSupport::Concern
included do
# some methods
end
end
end
# core/app/models/core/user.rb
module Core
class User < ActiveRecord::Base
include Core::UserHelper
end
end
however it says uninitialized constant Core::UserHelper. So it seems engine doesn't load its concerns by default, so I added it in the autoload paths
module Core
class Engine < ::Rails::Engine
config.autoload_paths += %W(#{Core::Engine.root}/app/models/core/concerns)
isolate_namespace Core
end
end
And now I end up this error: Unable to autoload constant UserHelper, expected myapp/core/app/models/core/concerns/user_helper.rb to define it
So what is wrong here? When I checked the guide http://edgeguides.rubyonrails.org/engines.html and it didn't have the concerns in concerns directory, but rather under lib/concerns and had all reference to concern using Core::Concerns::MyConcern, so is this where to put concerns in engine?
Thanks
Edit
Yury comment explained the issue, it seems that in rails engines concerns directory don't get any special treatment, and it is treated as a normal directory under models, so modules in it must be within Concerns namespace, and when including a concern, you have to include it with Concerns namesapace as well, if I understand right. I 'm surprised this is not mentioned in the docs.
The concern must reside inside the app/models|controllers/concerns/engine_name/concern_name.rb. This will autoload the concern.
To include the concern, include EngineName::ConcernName.
I had the same issue. Your mistake is that you are putting the concerns directory in the app/{models|controllers}/core directory, when it should be the other way round.
Instead of doing
app/{models/controllers}/core/concerns/user_helper.rb
change it to be
app/{models/controllers}/concerns/core/user_helper.rb
It took me a bit to figure out, because I intuitively thought it should also be under the engine_name directory.
Hope this helps.

rails 4 - require class in initializer or module that uses it - best practice

I'm a fairly new RoR dev and ran into a question about best practices for require ing files from lib in Rails 4.
Background:
As it stands, files in my app's lib don't get autoloaded. I want to require a helper class called rate_limiter that lives in a subdirectory of lib. I've also created a throttle module that handles routes related to rate limiting, and uses this rate_limiter class.
The throttle module is already required at the top of my application controller.
Question: to make sure rate_limiter gets loaded at start of app, what's better:
1) include an initializer rate_limiter.rb that simply says require rate_limiter to load class.
2) add require rate_limiter to the top of a different module throttle, which uses rate_limiter and which already gets required at the top of application controller.
Wondering about best practices for clarity and maintainability going forward.
Thanks for any suggestions!
I believe this would be a more Rails way to include desired files and folders.
# config/application.rb
module YourAppName
class Application < Rails::Application
# Custom directories with classes and modules you want to be autoloadable.
# config.autoload_paths += %W(#{config.root}/extras)
config.autoload_paths += Dir[Rails.root.join('lib')]
end
end
You probably could try the following scheme:
# config/application.rb:
# To make sure that your module namespace will be initialized without name collisions with files in your app directories
# require only root file and autoload other relative files in root file using features of ActiveSupport::Autoload
require_relative '../lib/my_module/my_module'
module AppName
class Application < Rails::Application
# Do not include all files in your lib. Require explicitly
# .
# ..
# - lib/my_module/my_module.rb - root file
# - lib/my_module/my_module - directory
config.autoload_paths += Dir[Rails.root.join('lib', 'my_module')]
end
end
Then in you module you can specify explicitly which files required and when
# lib/my_module/my_module.rb
module MyModule
extend ActiveSupport::Autoload
autoload :Configuration
autoload :SomeClass # at lib/my_module/my_module/some_class.rb
autoload :AnotherClass
eager_autoload do
autoload :Errors # at lib/my_module/my_module/errors.rb
autoload :BillError, 'my_module/errors'
end
end
It is worth to read an official guide to understand generic process of Rails constant lookup
To me, since this is going into your application controller which every request gets funneled through, I'd suggest adding this to your autoload paths.
In config/application.rb:
config.autoload_paths += %W(#{config.root}/lib/mymodule)

Include a custom module on Spree and Rails

I'm trying to add my module to my class_eval on Spree.
This is located on: lib/spree/core/app/models/spree/payment/processing.rb
Tried with the following:
module Spree
Payment.class_eval do
require GatewayError
end
end
I am trying to include the following located on: lib/spree/error_override.rb
module Spree
module GatewayError
end
end
The error I'm getting when I try to load the server is:
`block in <module:Spree>': uninitialized constant Spree::GatewayError (NameError)
Its my first time trying to include my own module to a class, would be awesome if someone can point me in the right direction.
Thank you in advance!
One solution would be to manually require the file during initialization process.
config/initializers/require.rb:
# put here all files that you want to require manually
require "#{Rails.root}/lib/spree/error_override.rb"
And that's it - your module is now ready to use ;)

Adding lib to 'config.autoload_paths' in Rails 3 does not autoload my module

I place a file name g.rb in side Rails.root/lib folder
The file content is like this:
module Google
end
Then I add
config.autoload_paths += %W(#{config.root}/lib #{Rails.root}/app/delayed_jobs)
to my Rails.root/config/application.rb
However, when I try to invoke Google from rails console, an exception is thrown. The exception goes away only if I execute require 'google'.
Why? Shouldn't my file is autoloaded and shouldn't I access the module without any extra require statement?
Hmm, I discovered an interesting thing. In order for Rails to auto load my class, the class name should be compliant to the file name and the folder structure.
For example, if I want to have Google module autoloaded, I must placed it inside google.rb, directly under /lib (incase I specify autoload from /lib).
If I want to auto load Google::Docs, then I either place it inside google.rb or google/docs.rb
I had a similar problem with getting my module to run on Heroku. In addition to the autoload naming convention stated by Stephen C, I found out that the module code must be require'd due to a threadsafe assumption made by the Rails' production environment on Heroku (even though threadsafe was commented out in my production.rb configuration file.) As soon as I require'd the module file before calling include on the module, everything started to work.
require 'mymodule'
include Mymodule
Please take a look at this excellent article on the subject of getting Modules to load correctly in Heroku (production).
That's because the point of autoload is not to 'require' everything up front (startup penalty). Classes are loaded as they are needed/referenced. In order to do this, you need some way to know where to look for the class. Otherwise, you would have to load every file in the autoload directory in advance to see what classes are declared. It's a tradeoff, but requiring everything in advance (as marbaq suggests) is not autoloading.
You can use the autoload command as provided by Ruby, which takes two arguments, the module to load (symbolized, i.e. :Google in your case), and the second argument is the filename, which would be g.rb if lib is in your load path ($:). See the Ruby docs for autoload.
Change config.autoload_paths to config.eager_load_paths
(based on Rails issue #6850 and Force reload! from lib directory in rails 3.2 console)
I faced the same problem just now, and my "solution" (or rather workaround) was to manually require every needed file from Rails.root/lib in my application.rb.
require 'lib/message'
require 'lib/store'
require 'lib/vault/vault.rb'
require 'lib/custom_loggers'
module MyApplication
class Application < Rails::Application
My next step would be to categorize the files in module folders as you mention.
i found this solution recently
config/application.rb
module AppName
class Application < Rails::Application
# Custom directories with classes and modules you want to be autoloadable.
config.autoload_paths += Dir[Rails.root.join('app', 'models', '{**}')]
config.autoload_paths += Dir[Rails.root.join('app', 'lib', 'extensions')]
end
end
the first config call induces rails to auto-load all sub-directories of the app/models directory
so now i can have /app/models/sub_directory/model.rb auto-loaded
(handy for organising an app with a large code base)
the second config call induces rails to autoload the lib/extensions directory
hope this helps
note: i believe this is rails 3 specific

Resources