Rails 3 autoload - ruby-on-rails

I have a class ConstData:
class ConstData
US_CITIES = ['miami', 'new york']
EUROPERN_CITIES = ['madrid', 'london']
end
Its stored under /lib/const_data.rb
The idea is that inside a model, controller or view I can do:
ConstData::US_CITIES to get the US_CITIES etc
Rails should load this class automatically, I got this from:
http://groups.google.com/group/rubyonrails-talk/browse_thread/thread/662abfd1df9b2612?hl=en
However this does not work. Can anyone explain me how to accomplish this ?

The post #daniel refers to is from 2008. Rails has changed since then.
In fact, quite recently. Rails3 doesn't load the lib/ directory automatically.
You can reactivate it quite easily though. Open config/application.rb And add, in the config (in the Application class) the followin :
config.autoload_paths += %W(#{config.root}/lib)
Then your lib/ dir will be autoloaded.

The reason autoload_paths didn't work for you and you were forced to do:
Dir["lib/**/*.rb"].each do |path|
require_dependency path
end
is because you forgot to namespace your class.
lib/awesome/stuffs.rb should contain a class/module like this:
class/module Awesome::Stuffs
....
but you had:
class/module Stuffs
....
Rails can only autoload classes and modules whose name matches it's file path and file name.
:)

config.autoload_paths did not work for me. I solved it by putting the following in ApplicationController:
Dir["lib/**/*.rb"].each do |path|
require_dependency path
end

Follow the solution for lib dir be autoloaded:
Remove config.threadsafe! from development.rb and production.rb;
Add in config/application.rb:
config.autoload_paths += %W(#{config.root}/lib)
config.threadsafe!
config.dependency_loading = true

Related

undefined local variable or method for method located in lib directory file

I have some code i've inherited and am in the process of upgrading it to Rails 3.1. I'm suuuuper close to done but I got a bug.
In Rails Console I run User.first and I get this error
undefined local variable or method `acts_as_userstamp' for #<Class:0x000000046bef50>
Now acts_as_userstamp is a method located on line two inside my User model
class User < ActiveRecord::Base
#TODO /lib is not loading??? or is it??? why this method not work in browser?
acts_as_userstamp
And is defined in a file called app/lib/model_modifications.rb.
Now I recently discovered that my app/lib folder was not being autoloaded in my application.rb file and I think that's been fixed...or has it? Is this file correct? Or no?
require File.expand_path('../boot', __FILE__)
require 'rails/all'
# evil outdated soap middleware, TODO: kill it with fire
# Does this have to be loaded BEFORE the first line???
$LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', "vendor", "soap4r"))
$LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', "vendor", "plugins", "soap4r-middleware", "lib"))
# evil outdated soap middleware, TODO: kill it with fire
require 'soap4r-middleware'
require File.join(File.dirname(__FILE__), '..', 'app', 'lib', 'soap.rb')
if defined?(Bundler)
# If you precompile assets before deploying to production, use this line
Bundler.require *Rails.groups(:assets => %w(development test))
# If you want your assets lazily compiled in production, use this line
# Bundler.require(:default, :assets, Rails.env)
end
module MyappDev
class Application < Rails::Application
# startup the lib directory goodies <-- IS THIS CORRECT???
# config.autoload_paths << "#{Rails.root}/lib"
# config.autoload_paths += %W( lib/ )
config.autoload_paths += %W(#{config.root}/lib)
config.autoload_paths += Dir["#{config.root}/lib/**/"]
# Configure the default encoding used in templates for Ruby 1.9.
config.encoding = "utf-8"
# Configure sensitive parameters which will be filtered from the log file.
config.filter_parameters += [:password]
config.middleware.use MyAPIMiddleware
end
end
I'm trying to debug this file as I post this now. Here is a peak at it's internal structure...(i've just included the overall structure for the sake of brevity)
app/lib/model_modificatons.rb
class Bignum
...
end
class Fixnum
...
end
class ProcessorDaemon
...
end
module ActiveRecord
module UserMonitor
...
end
module MyLogger
...
end
end
class Object
...
end
class Struct
...
end
class String
...
end
class Fixnum
...
end
class OpenStruct
...
end
class ActiveRecord::Base
def self.visible_columns
...
end
...
def self.acts_as_userstamp
logger.info "HI fonso - acts_as_userstamp is called"
include ActiveRecord::UserMonitor
end
...
protected
def self.range_math(*ranges)
...
end
end
class Array
...
end
class DB
...
end
If you can spot a problem with the overall structure or anywhere else please let me know.
So why is this method not found? I'm trying to debug it as I'm posting this and I'm getting nothing.
I suspect the file app/lib/model_modifications.rb is not being loading. That nothing in the /lib directory is being loaded..but how do I confirm this?
Thank you for reading this far, I hope I've not rambled on too much.
autoload_path configuration does not load all the given files on the boot but defines folders where rails will be searching for defined constants.
When your application is loaded, most of the constants in your application are not there. Rails have a "clever" way of delaying loading the files by using a constant_missing method on Module. Basically, when Ruby encounters a constant in the code and fails to resolve it, it executes said method. THe sntandard implementation of this method is to raise UndefinedConstant exception, but rails overrides it to search all of its autoload_paths for a file with a name matching the missing constant, require it and then check again if the missing constant is now present.
So, in your code everything works as expected and you need to load this extension file manually. If you want to have some code that executes on the application boot, put your file within config/initializers folder.
Aside: Try avoiding monkey patching whenever possible. It might be looking clever, but adding more methods to already overpopulated classes will not make them easier to use.

Rails: Loading custom class from lib folder in controller

I've created a file as lib/services/my_service.rb.
# /lib/services/my_service.rb
class MyService
...
end
I want to use it in app/controllers/my_controller
class MyController < ApplicationController
def method
service = MyService.new()
end
I'm getting an error that MyService is an uninitialized constant. I've tried to import it with
require '/lib/services/my_service.rb'
But I'm getting
cannot load such file -- /lib/services/my_service.rb
Edit: I have tried autoloading from application.rb using
config.autoload_paths << Rails.root.join('lib')
But no dice. Still getting uninitialized constant MyController::MyService
Ruby on Rails requires following certain naming conventions to support autoloading.
Rails can autoload a file located at lib/services/my_service.rb if the model/class structure was Services::MyService.
Change your lib/services/my_service.rb to:
module Services
class MyService
# ...
end
end
And use that class like this in your controller:
service = Services::MyService.new
Please note that depending on your Ruby on Rails version, you might need to add the lib folder to the list of folders which are queried when looking for a file to autoload:
# add this line to your config/application.rb:
config.autoload_paths << "#{Rails.root}/lib"
Read more about autoloading in the Rails Guides.
You probably need to enable the autoload from the files in the lib/ folder:
# config/application.rb
config.autoload_paths << "#{Rails.root}/lib"
If you prefer to do it "manually", then you can only require such file in the same file:
# config/application.rb
require './lib/my_service'
After this a restart is necessary.
there is a setting in config/application.rb in which you can specify directories that contain files you want autoloaded.
From application.rb:
# Custom directories with classes and modules you want to be autoloadable.
# config.autoload_paths += %W(#{config.root}/extras)
or
config.autoload_paths += Dir["#{config.root}/lib/**/"]
rails 3
Dir["lib/**/*.rb"].each do |path|
require_dependency path
end
Add this in your application.rb
config.eager_load_paths << Rails.root.join('lib/services')

Reload lib files without restart dev server in Rails 3.1

I have some modules inside the lib folder in rails i.e.:
/lib/myapp/lib/**
I am working on them in development, however each time I have to restart server. I have been through a number of different questions on SO but most of them are for not for rails 3.1
I currently have an initializer that does this;
if Rails.env == "development"
lib_reloader = ActiveSupport::FileUpdateChecker.new(Dir["lib/**/*"], true) do
Rails.application.reload_routes! # or do something better here
end
ActionDispatch::Callbacks.to_prepare do
lib_reloader.execute_if_updated
end
end
if Rails.env == "development"
lib_reloader = ActiveSupport::FileUpdateChecker.new(Dir["lib/myapp/lib/*"], true) do
Rails.application.reload_routes! # or do something better here
end
ActionDispatch::Callbacks.to_prepare do
lib_reloader.execute_if_updated
end
end
Is there a generic way to do this? Its very time consuming having to restart the server every single time!
Get rid of the initializer and in your application.rb file put following line:
config.autoload_paths += Dir["#{config.root}/lib/**/"]
One thing to watch out is that your module and class names should follow the naming convention for autoreload to work. for example if you have file lib/myapp/cool.rb, then your constant for class/module declaration in cool.rb should look like this:
Myapp::Cool
If you have file lib/myapp/lib/cool.rb and you want it to use Cool as class/module name instead of Myapp::Lib::Cool then your autoload should look like this:
config.autoload_paths += Dir["#{config.root}/lib/myapp/lib/**/"]
As long as you are running in devmode, rails will automatically reload all classes/modules that are in autoload path and follow naming conventions.
Add to application_controller.rb or your base controller:
before_filter :dev_reload if Rails.env.eql? 'development'
def dev_reload
# add lib files here
["rest_client.rb"].each do |lib_file|
ActiveSupport::Dependencies.load_file lib_file
end
end
Worked for me.

Namespaced modules and Rails 3.1.3 autoload_path

I'm having some trouble to namespace a module that I include in a model.
in /app/models/car.rb
class Car
include Search::Car
end
in /lib/search/car.rb
module Search
module Car
include ActiveSupport::Concern
# methods in here
end
end
in /config/application.rb
config.autoload_paths += Dir["#{config.root}/lib/**/"]
config.autoload_paths += Dir["#{config.root}/lib/search/*"]
The weird thing is that I don't get any errors directly when I fire up the server.
But if I refresh the browser after a while I get this error:
Expected #{Rails.root}/lib/search/car.rb to define Car
The nature of the problem indicates that it has something to do with:
/config/environments/development.rb
config.cache_classes = false
I also tried put a file search.rb directly in /lib where I define Search:
module Search
# Put shared methods here
end
What am I doing wrong?
UPDATE:
Ok, turns out that if I rename Search::Car to Search::CarSearch it works.
Is it not possible to have Modules/Classes of the same name in a different scope?
The error is coming from your autoload_paths. config.autoload_paths += Dir["#{config.root}/lib/**/"] will add all directories and their subdirectories under lib directory. meaning that you are telling rails to autoload lib/search/ directory, therefore car.rb under that directory is expected to define Car and not Search::Car. In order for rails to expect lib/search/car.rb to define Search::Car, you need to autoload lib/ directory and not lib/search. if you change you autoload to config.autoload_paths += Dir["#{config.root}/lib/"] and put search.rb in lib/ with following code:
module Search
require 'search/car'
end
then rails will understand and expect lib/search/car.rb do define Search::Car and referencing Car module/class in other places of your code will not reference to this car.rb.
You should remove this line (you should only have autoload for lib directory):
config.autoload_paths += Dir["#{config.root}/lib/search/*"]

cant load lib directory modules - uninitialized constant - rails 2 to rails 3 upgrade

I'm currently migrating an application in rails v2 to v3
In my lib/ i've some modules in subdirectories, for example,
i've the lib/search/host_search.rb
with a
module HostSearch
def do_search(args)
#...
end
end
then I need to use it in a controller named Discovery::HostController < ApplicationController :
def search_results
output = HostSearch.do_search(:search_string => #search_string,
:page => params[:page],
:user => #current_user)
#...
end
But have I get:
uninitialized constant Discovery::HostController::HostSearch
..I tried to put this lines in application.rb but it doesn't work..
config.autoload_paths += %W(#{config.root}/lib)
config.autoload_paths += Dir["#{config.root}/lib/**/"]
I found that moving the module to the lib folder or explicitly including the folder to load worked, in your case
config.autoload_paths += %W(#{config.root}/lib/search)
I think there's something syntaxical that we are missing. Another thing is that if you don't want to mess with the application.rb file, require the file, which if I remember, takes the file path from the lib folder eg: search/host_search <- check that.
I think if you put the HostSearch module under a search subdir, (ie in lib/search/host_search.rb), then you need to namespace it:
module Search
module HostSearch
end
end
If you don't want to namespace it, you can should move the file into the lib root: lib/host_search.rb.
See also: https://stackoverflow.com/a/19650564/514483

Resources