I'm trying to define a constant in an initializer file and to use it into a model.
config/initializers/constants.rb
DEFAULT_EVENT_DURATION = 15
app/models/event.rb
class Event < ActiveRecord::Base
before_validation :set_end_and_allday
[...]
def set_end_and_allday
self.allDay ||= false
self.end_event ||= self.start + DEFAULT_EVENT_DURATION.minute
end
end
However, when it try to create a new event, it displays the following error in the logs:
NameError - uninitialized constant Event::DEFAULT_EVENT_DURATION
Am I doing something wrong?
I've made some searches on google, but I didn't find any solution (except defining constant into the model and not in the initializer... and that's not what i want to do).
It was just a scope problem: constant was in the root scope but it was searching the constant in the controller scope.
A simple '::DEFAULT_EVENT_DURATION' solved the issue.
Related
I have these 2 files in a large system, both are located in PackA
people.rb
module People
class HobbyValueObject
end
end
job.rb
module People
class Job
end
class CityValueObject
end
end
I am trying to use CityValueObject in a different module like this,
Module is in PackB
work.rb
module Profile
class Work
....
def calculateTaxes
...
a = People::CityValueObject....
end
end
end
But it's giving me an error saying,
NameError: uninitialized constant People::CityValueObject
Did you mean? People::HobbyValueObject
Why is not being able to fine CityValueObject but can find HobbyValueObject just fine?
How do I make it find the object that I am intending to use?
I am not explicitly declaring any requires or includes
I was able to resolve this by adding require at the top while using full path file name.
require './packs/people/app/public/people/job'
Disclaimer : I know that it's a very bad pattern, I just want to understand why I have the following behaviour and the mechanics behind it.
Lets have one class with some constants / methods
one concern
one monkey patch that include that concern into my first class
I put all of the following in one rails model (under app/modela/a.rb)
class A
MY_CONST = "const"
def self.hello
"world"
end
end
module MyConcern
extend ActiveSupport::Concern
included do
byebug # Here I want to try many things
end
end
class A
include MyConcern
end
Then I open my console and run the following to load my class :
[1] pry(main) > A
First I'm my A Class is loaded, then the MyConcern module, then the monkey patch.
When I enter my byebug I have some weird behaviour
(byebug) self
A # Important : I'm in the scope of my A class
(byebug) hello
"world" # so far so good, my A class is loaded and have a world class method
(byebug) A::MY_CONST
"const" # Obiously this is working
(byebug) self::MY_CONST
"const" # When I Explicitly access it through `self`, it's also working
(byebug) MY_CONST
*** NameError Exception: uninitialized constant MyConcern::MY_CONST
nil # Here for some reason, and that's what I want to understand, I can't access my const, even if `self == A`
I want' to know why constant are not working the same way. Why ruby isn't able to find this const. My scope is my A class, self == A, so why can't I access my constant?
ps : Rails.version => "6.0.0"
I have the following classes in my rails 4 app:
class ReceiptDocument < ActiveRecord::Base
#foo
self.inheritance_column = :document_type
has_and_belongs_to_many :donations
protected
def self.inherited(subklass)
subklass.inherit_attributes(#foo)
end
def self.inherit_attributes(foo)
#foo = foo
end
end
class ReceiptRequest < ReceiptDocument; end
class ReceiptResult < ReceiptDocument; end
The class instance variable #foo is set once at class definition, and should have the same value in all subclasses. I added the inherited override so that value would be accessible from both ReceiptRequest and ReceiptResult.
However, now when I call ReceiptRequest.new, I get:
pry(main)> DonationReceiptRequest.new
NoMethodError: undefined method `[]' for nil:NilClass
from /gems/activerecord-4.1.5/lib/active_record/relation/delegation.rb:9:in `relation_delegate_class'
If I comment out that override, things return to normal. However, I can no longer share that value across all subclasses of ReceiptDocument.
Any insight would be greatly appreciated.
Finally got this sorted.
The error seemed to be pointing me at some behind the scenes work that ActiveRecord was doing, so I dug in a bit further.
It seems that setting self.inheritance_column most likely overrides the inherited method. Honestly, I'm not sure what work is being done that my override was stomping on. But redefining that method as below fixed the issue:
def self.inherited(subklass)
super # <--
subklass.inherit_attributes(#foo)
end
Ripping my hair out on this one:
app/models/concerns/soft_delete.rb:
module SoftDelete
extend ActiveSupport::Concern
module ClassMethods
def testing_a_class
pp "Ima class method"
end
end
def testing_an_instance
pp "Ima instance method"
end
end
class User < ActiveRecord::Base
include SoftDelete
end
app/models/user.rb:
class User < ActiveRecord::Base
testing_a_class
end
Now, in the rails console:
x = User.first # I expect "Ima class method" to be printed to the screen
NameError: undefined local variable or method `testing_a_class' for User(no database connection):Class
I don't know where you saw this idea of including a module in the same file where it's defined, but you must not do it (in rails), because of how rails works (auto-lazy-loading).
Rails doesn't load all classes on startup. Instead when you reference a class that doesn't yet exist, rails attempts to guess where it might be located and loads it from there.
x = User.first
Before this line, constant User does not exist (assuming it wasn't referenced before). When trying to resolve this name, rails will look for file user.rb in each of autoload_paths (google it up). It will find one at app/models/user.rb. Next time you reference User, it will just use this constant and will not look it up in the filesystem.
# app/models/user.rb:
class User < ActiveRecord::Base
testing_a_class
end
The definition that was found contains only an invocation of some unknown method (hence the error). Code in your concern file was not loaded and will never be loaded. To fix this, include the concern in the model file.
# app/models/user.rb:
class User < ActiveRecord::Base
include SoftDelete
testing_a_class
end
Now it should work.
In a Rails 3.1 project, I have a model class with a custom validator:
class Car < ActiveRecord::Base
validate :road_must_exist_nearby, :on => :create
# ...
def not_a_validator_method
Road.exists_nearby?
end
def road_must_exist_nearby
if !Road.exists_nearby?
# ...
end
end
end
When I attempt to save my instance of Car ...
> car = Car.new
> car.save
I get the following error:
NameError: uninitialized constant Car::Road
Why does calling Road.exists_nearby? from a normal instance method work?:
> car.not_a_validator_method
=> true
And why does calling it from a validator method raise an error, as though Rails believes Road should be called through Car?:
> car.road_must_exist_nearby
NameError: uninitialized constant Car::Road
And how can I make the validator method work?
I'm only guessing, but I'd say it's a namespace/scope issue. Rails is interpreting the "Road" constant as existing in the scope of Car (ie Car::Road). You can probably get around it by referencing the global namespace using: "::Road"