RoR autoload sub directories - ruby-on-rails

I have created a "services" dir in app/ where I have created some classes (services). Now it's looks like this :
-app
-services
-class1
-class2
-class3
-class4
For now, I have added app/services in config/spring.rb
%w(
.ruby-version
.rbenv-vars
tmp/restart.txt
tmp/caching-dev.txt
app/services
app/errors
).each { |path| Spring.watch(path) }
So my classes in services are loaded.
But now, I want to do this :
-app
-services
-dir1
-class1
-class2
-dir2
-class3
-class4
I got error :
uninitialized constant TransactionService::AuthorizeRequest
How autoload a dir and subdir ?

Rails tries to guess namespaces by dirnames & filenames. So, to have a TransactionService::AuthorizeRequest class name, you should have the exact following structure:
app
- services
-- transaction_service
--- authorize_request.rb
Your class sould looks like :
module TransactionService
class AuthorizeRequest
end
end

Related

Running webpacker:compile for a engine in my host app causes rails to abort

I have a rails engine/plugin in which i am trying to use webpacker using THIS article as a guide. So basically in my engine, i have the following code :-
lib/saddlebag.rb
require "saddlebag/engine"
module Saddlebag
# ...
class << self
def Webpacker
#Webpacker ||= ::Webpacker::Instance.new(
root_path: Saddlebag::Engine.root,
config_path: Saddlebag::Engine.root.join('config', 'webpacker.yml')
)
end
end
# ...
end
and in the lib/saddlebag/engine.rb file i have the following code :
module Saddlebag
class Engine < ::Rails::Engine
isolate_namespace Saddlebag
# use packs from saddlebag via Rack static
# file service, to enable webpacker to find them
# when running in the host application
config.app_middleware.use(
Rack::Static,
# note! this varies from the webpacker/engine documentation
urls: ["/saddlebag-packs"], root: Saddlebag::Engine.root.join("public")
)
initializer "webpacker.proxy" do |app|
insert_middleware = begin
Saddlebag.webpacker.config.dev_server.present?
rescue
nil
end
next unless insert_middleware
app.middleware.insert_before(
0, Webpacker::DevServerProxy, # "Webpacker::DevServerProxy" if Rails version < 5
ssl_verify_none: true,
webpacker: Saddlebag.webpacker
)
end
end
end
Also i have all of the files required by webpacker mainly :-
config/webpacker.yml and config/webpack/*.js files
bin/webpack and bin/webpack-dev-server files
package.json with required deps.
So the engine and my actually app are in sibling directories so:-
saddlebag
open-flights (main app)
in open flights i link saddlebag with the following line in the gem file :-
gem 'saddlebag', path: '../saddlebag'
Now when i run bin/rails saddlebag:webpacker:compile , i get the following error :-
rails aborted! Don't know how to build task
'saddlebag:webpacker:compile' (See the list of available tasks with
rails --tasks)
Why am i getting this error i have webpacker as a dependency in my saddlebag app. So not sure why this error still occures.
P.S. I found a similar guide for rails engine for enabling webpacker HERE (but uses docker)

Rspec uninitialized constant for class nested inside module - Ruby on Rails

In a Rails project, I have created a new class inside the lib directory, this class is namespaced inside a module. When creating a spec file for it, I'm seeing NameError: uninitialized constant MyNamespace.
Here is my folder structure
app/
...
lib
my_namespace
my_new_class.rb
another_namespace
another_old_class.rb
spec
lib
my_namespace
my_new_class_spec.rb
another_namespace
another_old_class_spec.rb
Here the (abbreviated) contents of:
lib/my_namespace/my_new_class.rb
module MyNamespace
class MyNewClass
end
end
spec/lib/my_namespace/my_new_class_spec.rb
RSpec.describe MyNamespace::MyNewClass do
it "is true"
expect(true).to eq(true) # irrelevant at this point
end
end
The reason I included another_old_class_spec.rb is that its tests run without issue and I can't find anywhere that it's explicitly loaded or required in the test setup (in case that might be a potential issue).
When running the test with bundle exec rspec spec/lib/my_namespace/my_new_class_spec.rb or even bundle exec rspec spec/lib/my_namespace/ I get
An error occurred while loading ./spec/lib/my_namespace/my_new_class_spec.rb
Failure/Error:
RSpec.describe MyNamespace::MyNewClass do
NameError:
uninitialized constant MyNamespace
Like Georgiy Melnikov implied in his comment, by default the /lib directory is not in autoload paths, so the constant MyNamespace is not automatically resolved.
You basically have two options to fix this:
explicitly require the file with require lib/my_namespace/my_new_class at the top of the spec file
add lib/ to autoload paths (nowadays this is discouraged)

Rails same file name for different classes

Having model Price (models/price.rb)
class Price
end
Also in lib directory I have import/detector/price.rb file
class Import::Detector::Price
end
Lib directory added to autoload paths via
config.autoload_paths += Dir["#{config.root}/lib/**/"]
So running Price.new I get error
Unable to autoload constant Price, expected lib/import/detector/price.rb to define it.
Import::Detector::Price.new is ok
What was my mistake?
UPD.
The most interesting
Also having this file models/car/property/price.rb
class Car::Property::Price
end
And everything ok with it. Car::Property::Price is available.
Try
config.autoload_paths += Dir["#{config.root}/lib"]
instead of
config.autoload_paths += Dir["#{config.root}/lib/**/"]
Using **, Dir will return every directory under lib and will put them all (as root directories) in the load path. It should only be the main lib directory in the load path as rails will work out the subdirectories using the namespace.
Rails autoloading — how it works, and when it doesn't

My libraries are not being loaded on production

Everything works fine locally.
In my application.rb :
module Maestra
class Application < Rails::Application
config.autoload_paths += Dir["#{config.root}/lib/MyLib/**/"]
Then I deploy, and in console MyLib is an undefined class.
So if I change my application.rb to :
config.autoload_paths += Dir["#{config.root}/lib/**/"]
Then MyLib is a known class but it has no namespaces nor methods.
My directories are set up as so :
+ Lib
+ MyLib
MyLib.gemspec
+ lib
common.rb
my_custom_namespace.rb
So on my local I can very easily do : MyLib::MyCustomNamespace, but remotely, with the latter config in my application.rb, that namespace does not exist.

Having a module and class with the same name

I have a module stat that exists in the directory structure: lib/stat_creator/stat/
In lib/stat_creator/stat.rb I have the files in the lib/stat_creator/stat/ directory that I require, as well as:
module StatCreator
module Stat
end
end
When I use that module I refer to the classes as
StatCreator::Stat::Foo.new
Now I want a root Stat class that lives in app. I've made my Stat class in app/models and set it up in routes.rb. But if I go to rails console and try to use the Stat class in app/models like:
Stat.by_user_id("ID")
I get the error: LoadError: Expected ../lib/stat_creator/stat.rb to define Stat
I thought the point of using namespaces was to avoid this kind of conflict, so I don't understand what I"m doing wrong.
I'd do:
::Stat.by_user_id("ID")

Resources