Autoload custom exceptions files with RoR - ruby-on-rails

In my app/ directory I have a folder services. To autoload my files in the service folder, I added 'app/services' in my 'config/spring.rb'
%w(
.ruby-version
.rbenv-vars
tmp/restart.txt
tmp/caching-dev.txt
app/services
).each { |path| Spring.watch(path) }
It's work fine. But now, I want to create a sub dir for my custom exceptions (in app/services/errors/). But when I try to add a new line in my spring.rb :
%w(
.ruby-version
.rbenv-vars
tmp/restart.txt
tmp/caching-dev.txt
app/services
app/services/errors
).each { |path| Spring.watch(path) }
It's not working, I got some :
NameError:
uninitialized constant SixError
Here my custom error file (app/services/errors/six_error.rb):
class SixError < RuntimeError
end
class NilTokenError < SixError
end
class SixRequestFailed < SixError
end
class NoAliasRequestPendingError < SixError
end
class AmountLessThanZeroError < SixError
end
class NilAliasError < SixError
end
And this is how I called this :
SixError::SixRequestFailed

Rails is loading class in subdir with a namespace corresponding to the dirname.
If you have this structure :
-app
--services
---errors
----six_errors.rb
Rails expecting the file six_errors.rb to declare class upon the namespace Errors.
In your case you should declare all your errors class in a module named Errors.
module Errors
class SixError < RuntimeError; end
end

Related

Require module throwing error in Rails 5

I am attempting to create a permissions structure for users in my application. I created a permissions.rb file in the lib/ directory in my rails application.
When I try to include Permissions in my user model I am getting this error.
This is what I have in the user model.
class User < ApplicationRecord
include Permissions
...
end
How can I include this file and its methods without getting this error?
To include modules under lib folder you will need to add your lib folder in autoload_path in your application.rb
config.autoload_paths += %W( #{config.root}/lib/)
add this line in your application.rb.
I think it would be good if you use autoload file when application start then it would like to on the application.rb
config.autoload_paths << Rails.root.join('lib')
Or you can use user.rb
class User < ApplicationRecord
load File.join(Rails.root, 'lib', 'permissions.rb')
end
The module would look like this, always make sure the naming conventions is right like if run module name on the console with underscore then he would give your file name, see the below if your module name is Permissions then
Loading development environment (Rails 5.1.4)
2.3.4 :001 > "Permissions".underscore
=> "permissions"
your file name is permissions.rb
#=> permissions.rb
module Permissions
...
def self.method #=> method name instead of the method
#=> code staff here
end
or
def method #=> method name instead of the method
#=> code staff here
end
...
end
Hope it helps

How to require and auto load files properly

I'm running into quite a few errors around how to require files property. Hoping for some insight.
There are files as so:
app/models
model.rb
app/workers
parent_worker.rb
app/workers/directory_1
directory_worker.rb
foo_worker.rb
bar_worker.rb
class DirectoryWorker < ParentWorker
end
class FooWorker < DirectoryWorker
def method_called_by_model
end
end
When I call the method, method_called_by_model I get the following error:
NameError: uninitialized constant Model::FooWorker
I've added the following to application.rb, didn't add app/workers since it should be loaded automatically according to the documentation.
config.autoload_paths << "#{Rails.root}/app/workers/directory_1"
When I require_relative the worker files in the model I get the following error referring to the inherited class being unknown:
NameError: uninitialized constant DirectoryWorker
from project/app/workers/directory_1/FooWorker.rb:2:in `<top (required)>'
Any have any ideas what I can do?
You need to namespace those workers since they are inside a directory.
First remove the autoload call you added.
Here's how the files should be named and what they should look like inside.
# app/workers/parent_worker.rb
class ParentWorker
end
# app/workers/directory_1/directory_worker.rb
class Directory1::DirectoryWorker < ParentWorker
end
# app/workers/directory_1/foo_worker.rb
class Directory1::FooWorker < Directory1::DirectoryWorker
def method_called_by_model
end
end
# app/workers/directory_1/bar_worker.rb
class Directory1::BarWorker < Directory1::DirectoryWorker
end

rails require local file

I have rails project. And I want to add code to class MainParserPlugin ( path : app/controllers/admin/main_parser_plugin.rb") from class ParserPlagin (path : "app/controllers/admin/parser_plugin.rb")
main_parser_plugin.rb:
require 'parser_plugin'
class Admin::MainParserPlugin < ApplicationController
#Some code
end
But it appear an error :
cannot load such file -- parser_plugin
Can you tell me what path I must put, to work it well?
Within config/application.rb you'll need to add any subdirectories under app/models to the autoload_path by adding the following line:
config.autoload_paths += Dir["#{config.root}/app/models/**/"]

Rails 3.2.9 and models in subfolders

Since rails 3.2.9 I'm unable to store models in subfolders. In my app I have this tree:
models
-type_models
-assets
-user
-concerns
Also in application.rb there is
config.autoload_paths += Dir["#{config.root}/app/models/*"]
All things was ok till rails 3.2.9. Now I have "Unknown constant" error.
I don't want to namespace tons of model and fix all app to use namespaced models.
Warning: Error loading /var/www/my_app/app/models/type_models/context_type.rb:
uninitialized constant TypeModels::ContextType
file context_type.rb:
class ContextType ... end
Try to use:
config.autoload_paths += Dir["#{config.root}/app/models/**/"]
in config/application.rb:
config.autoload_paths += %W(type_models assets user concerns).map { |folder| "#{config.root}/app/models/#{folder}"}
in models/type_models/context_type.rb:
class TypeModels::ContextType < ActiveRecord::Base
...
end
Restart Rails and you're all set!
Wrap your class ContextType ... end to module:
module TypeModels
class ContextType
# blah blah
end
end

Forcing rails to autoload class

I have several small classes that are in a single file in /app/models, similar to:
# /app/models/little_class.rb
class LittleClass; ...do stuff; end;
class AnotherLittleClass; ...do stuff; end;
Rails only seems geared to autoload classes in files reflecting the class name. So referencing AnotherLittleClass outside of the file raises "unitialized constant" errors as below until LittleClass is referenced:
irb(main):001:0> AnotherLittleClass
NameError: uninitialized constant AnotherLittleClass
irb(main):02:0> LittleClass
=> LittleClass
irb(main):03:0> AnotherLittleClass
=> LittleClass2
It would be a pain and messy to split them into individual files. Is there a way to autoload these classes, so referencing AnotherLittleClass without LittleClass doesnt raise an error?
You could put them into a module and use them within this namespace SomeLittleClasses::LittleClass.do_something
# /app/models/some_little_classes.rb
module SomeLittleClasses
class LittleClass
def self.do_something
"Hello World!"
end
end
class AnotherLittleClass
def self.do_something
"Hello World!"
end
end
end
Try this trick:
1.9.2p312 :001 > AnotherLittleClass.new
# => NameError: uninitialized constant AnotherLittleClass
1.9.2p312 :002 > autoload :AnotherLittleClass, File.dirname(__FILE__) + "/app/models/little_class.rb"
# => nil
1.9.2p312 :003 > AnotherLittleClass.new
# => #<AnotherLittleClass:0xa687d24>
These are your choices, as I see it:
split your file up into one file per class, put them in a dir named according to the rails convention (SomeClass => some_class.rb) and in a startup file (say, create a file in config/initializers), call:
autoload_paths Rails.application.config.root + "/path/to/lib"
add something like this to a startup file:
%W[
Class1 Class2
Class3 Class4 Class4
].map(&:to_sym).each dp |klass|
autoload klass,Rails.application.config.root + "/path/to/lib/file"
end
This of course will have to be updated each time a new class is added to the file.
Move all of the classes into a module/class namespace and call autoload to add it as above
just load the whole file up-front in a startup file with require. Ask yourself: does the extra effort warrant delaying the load of this file?
The following file app/models/statistic.rb is given :
class Statistic
# some model code here
end
class UsersStatistic < Statistic; end
class CommentsStatistic < Statistic; end
class ConnectionsStatistic < Statistic; end
Create a file config/initializers/autoload_classes.rb and add the following code:
# Autoloading subclasses that are in the same file
# This is the normal way to load single classes
#
# autoload :UsersStatistic, 'statistic'
# autoload :CommentsStatistic, 'statistic'
# autoload :ConnectionsStatistic, 'statistic'
# This is the most dynamic way for production and development environment.
Statistic.subclasses.each do |klass|
autoload klass.to_s.to_sym, 'statistic'
end
# This does the same but loads all subclasses automatically.
# Useful only in production environment because every file-change
# needs a restart of the rails server.
#
# Statistic.subclasses

Resources