Cannot access models from /lib in Rails - ruby-on-rails

I make a script to try some functions. But I cannot use models in lib. Interesting is, that I already have an lib, and there it works fine with the mostly same code(?).
// script/tags.rb:
require File.expand_path('../../config/application', __FILE__)
require 'company_tags'
host = ARGV[0] || 'team1.crm.tld'
c = CompanyTags.new(host)
c.run
// lib/company_tags.rb
class CompanyTags
def initialize(host)
#site = Site.where(host: host).first
end
def run
comp = #site.companies.first
comp.tag_list.add("tag1")
comp.general_list.add("tag_general")
comp.save!
p comp.tag_list
end
end
Error: /lib/company_tags.rb:3:in `initialize': uninitialized constant CompanyTags::Site (NameError)

You need to require the environment, not the application.
require File.expand_path('../../config/environment', __FILE__)
require 'company_tags'
The environment will load all the dependencies, including the application, and it will bootstrap the application.

Just an idea, but try changing Site.where(host: host).first to ::Site.where(host: host).first. Putting the :: in front, causes ruby to look for Site in the global namespace instead of as a constant defined in CompanyTags.

You can add a simple configuration to config/application.rb:
# Autoload lib/ folder including all subdirectories
config.autoload_paths += Dir["#{config.root}/lib/**/"]
Check this question out for more details.

In my previous answer, I thought you were running rails console. Your main issue is that the Site class is not required. Here is how requiring files to your classes work.
Through the require_all function
require_all(MY_CLASSES_DIRECTORY)
Or by requiring each class manually:
require 'Class_NAME.rb'
Notice that the Site class is not required anywhere.
For more details, check this link

Related

Unable to autoload constant A, expected <path> to define it rails

I'd searched internet on this problem, and the answers say that the most common things are:
Rails naming conventions are begin violated. For example: filename is hello_world.rb and the classname is Hello_World instead of HelloWorld.
In config.autoload_paths in application.rb there is no path required.
None of these cases are mine: I got file under /lib/admin_analytics.rb and module name AdminAnalytics. Also I have config.autoload_paths << Rails.root.join('lib) in application.rb.
But in development mode, when I change the code and refresh the page (making request) the
Unable to autoload constant AdminAnalytics, expected /lib/admin_analytics.rb to define it.
error comes. How to fix this? Thanks in advance!
Ruby version 2.6.0
Rails is 5.2.5
The beginning of the module
module AdminAnalytics
def self.compute_numbers(options = {})
require 'admin/compute_numbers'
# ComputeNumbers.debug = true
ComputeNumbers.send(options[:method], options)
end

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 3, app/lib not loaded with rspec

I have a controller "A" which requires a file in a subdirectory of app/lib (ex: app/lib/a_folder/my_class.rb).
So I did something like this :
require 'a_folder/my_class'
class AController < ApplicationController
# Some stuff using MyClass
end
It works well when I use the application, but doesn't work when I launch RSpec.
This is how my RSpec file looks:
require 'spec_helper'
require 'lib/import_functions' # Rails.root/spec/lib/import_functions.rb
RSpec.describe AController, type: controller do
# My tests routines
end
When I start rspec it tells me the require in the controller file doesn't found the file (`require': cannot load such file), while it works well when I start the app.
I've added a puts $LOAD_PATH just before the require and it appears that Rails.root/app/lib is not present.
I use Rails 3.2 and rspec-rails 3.2.
Does anyone have any idea why it happens and how to fix it please ?
Thank you for your future answers.
lib files are not auto loaded. You can put the following configuration in your application.rb, it has a problem also it will load all files under lib directory.
config.autoload_paths += "#{Rails.root}/lib/"
Or you can load your lib files in your RSpec as following code
require_relative "../../lib/a_folder/my_class.rb"
or
require 'lib/a_folder/my_class.rb'

How to require some lib files from anywhere

I'll explain my situation.
Here is my file tree in my rails application :
lib/my_module.rb
require 'my_module/my_file'
module My_module
end
lib/my_module/my_file.rb
class Tweetag::Collector
(...)
end
I've made a ruby script that I've put in config/jobs/
I really don't understand how I am supposed to require the file my_file.rb in this file.
require '../../my_module/my_file.rb'
It gives me `require': cannot load such file
Same error with just require 'my_module' which is what I do in my controllers...
Someone here to explain to me ? Thanks a lot
You can autoinclude everything under the lib folderand avoid these problems:
Type this your file in config/application.rb
config.autoload_paths += %W(#{config.root}/lib)
config.autoload_paths += Dir["#{config.root}/lib/**/"]
If you want to require only a specific file then,
do something relative to Rails root like this
for example: --
lib/plan.rb
module Plan
...some code...
end
and if you want to require it only in some model, say app/models/user.rb
do in user model
require "#{Rails.root}/lib/plan"
class User < ActiveRecord::Base
include Plan
end
if you want it to be available everywhere
one solution is given by #VecchiaSpugna
or you can create a ruby file in config/initializers folder
and require all file over there one by one
OR
try this
require '../../my_module/my_file'
instead of
require '../../my_module/my_file.rb'
You don't need to specify extension for a file in require.
I think there are two solutions.
1) Add the lib path to the search path.
In ruby:
$:.unshift('../../my_module/lib')
Then you can require 'my_module.rb'
I think Vecchia Spugna answer is the rails-version of my ruby-answer. (I'm not familiar with rails).
2) Another solution:
In your lib/my_module.rb you require my_file. This file is located relative to your my_module.rb? Then use require_relative:
require_relative './my_module/my_file'
Just chiming in because it took me forever to figure this out because very little solutions worked.
• I had to use plain old require. I put it in the config/application.rb file.
patching_file_path = File.expand_path("./lib", Dir.pwd)
Dir[patching_file_path+'/*.rb'].each {|file| require file }
• I also put a temporary puts "I'm Working! in the file I'm trying to require so I can check the console to see if it's actually loading.
• Also, if you're using spring loader, before you start your console you should do bin/spring stop in your terminal before you start your rails console. Otherwise, it won't load new files.
Similar to require_relative,
# inside lib/my_module.rb
require File.expand_path('./my_module/my_file', File.dirname(__FILE__))
This expands the path of current file directory and add the relative file path to be required.

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