I have model as follows
app/models/views/def_usage.rb
class Abc
class Def < ActiveRecord::Base
self.table_name = 'vSomeview'
end
end
I am trying to create a factory girl for this
spec/factories/views/def_usage.rb
FactoryGirl.define do
factory :def_usage, class: Abc::DefUsage do
......
end
end
I am getting error uninitialized constant Abc::DefUsage (NameError)
I tried changing class: Views::Abc::DefUsage or Views::DefUsage but no luck. i am getting that error when i am trying to do rails console. why i am getting that error?
Your path needs to match your module/class hierarchy.
If you want your class to be in app/models/views/def.rb, then your class needs to be Views::Def.
If you want your class to be Abc::Def, your path needs to be app/models/abc/def.rb.
If you want your class name to be DefUsage, your file name needs to be def_usage.rb.
You can't use arbitrary paths and class names. They need to match if you want Rails to automatically load constants for you.
Related
In my Rails 5 app I have a module in app/lib
module LibClass
CONSTANT_NAME = ‘somevalue’
end
Then in a model I reference the module:
class SomeModel < ApplicationRecord
def lib_class_constant
LibClass::CONSTANT_NAME
end
end
Everything works as expected when I call lib_class_constant on an instance of a SomeModel in console
But if I do the same in a view:
<%= some_model_instance.lib_class_constant %>
I get an error along the lines of:
uninitialized constant SomeModel::LibClass
If I reference the module directly in the view:
<%= LibClass::CONSTANT_NAME %>
I get an error along the lines of:
uninitialized constant ActionView::CompiledTemplates::LibClass
What am I missing here?
Have you tried the line include LibClass right after class SomeModel < ApplicationRecord ?
Otherwise have you checked that models and files have the right names? i.e. sometimes you rename a model without renaming the file accordingly or vice versa...
I have a class like this
class SMTPProvider < ActiveRecord::Base
self.table_name = 'smtp_providers'
And the corresponding factory for this is
FactoryGirl.define do
factory :smtp_provider, class: 'SMTPProvider' do
end
end
FactoryGirl.create(:smtp_provider) works fine. But the problem is when using this in another factory
FactoryGirl.define do
factory :based_on, class: 'AttackPackage' do
smtp_provider_id { FactoryGirl.create(:smtp_provider) }
end
end
Here is the error
Unable to autoload constant SmtpProvider, expected
/home/vamsi/code/scope2/app/models/smtp_provider.rb to define it
from /home/vamsi/.rbenv/versions/2.3.1/lib/ruby/gems/2.3.0/gems/activesupport-5.1.1/lib/active_support/dependencies.rb:511:in `load_missing_constant'
It's trying to load SmtpProvider, but my class name is SMTPProvider, which I have mentioned in the smtp_provider factory
Due to the way RoR autoloads classes, the names you're using misalign with the autoloader. The autoloader expects there to be a _ before every capital letter (except the first).
Right now you have a file name smtp_provider.rb and a class name SMTPProvider which mismatch. The filename for SMTPProvider is s_m_t_p_controller.rb and the class name for smtp_provider.rb is SmtpProvider
Here's a class to file name method I made to show this:
class String
def upper?
self == self.upcase
end
end
module ClassFileName
def self.to_file_name(class_name)
class_name = class_name.chars
.inject do |file_name, char|
char = "_#{char}" if char.upper?
file_name << char
end.downcase
"#{class_name}.rb"
end
end
You can run it like this:
ClassFileName.to_file_name('SMTPProvider')
Which outputs: s_m_t_p_provider.rb
You have a few options to get them to line up:
create a s_m_t_p_controller.rb symlink with ln -s app/models/smtp_provider.rb app/models/s_m_t_p_provider.rb
mv app/models/smtp_provider.rb app/models/s_m_t_p_provider.rb move the file entirely
Rename class to SmtpProvider so it autoloads properly (Note: will have to update the code anywhere SMTPProvider is currently used)
I like option 3 the most since both the class and file name look "clean" to me.
I'm trying to create a new model in spree extension. I generated a model and it is in /spree_extension/app/models/my_class.rb:
module Spree
class MyClass < Spree::Base
belongs_to :product
end
end
But when I start my application, there is no Spree::MyClass, I get this error:
NameError: uninitialized constant Spree::MyClass
I tried moving my_class.rb to "spree" directory, but nothing helps.
Most probably, you need to put your class into:
/spree_extension/app/models/spree/my_class.rb
As rails is always expecting to find classes inside file with the same name, inside folder that has the module name.
The problem was in fact I created a table my_class.
Since I renamed it to spree_my_class, it works.
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.
I'm trying to model some UI elements.
I've created a series of classes in /app/models/wrappers/*
For this post i'm going to focus on a class called InputTextVO
I have:
class InputTextVO
...
end
/app/models/wrappers/InputTextVO.rb
When I try and initialize it in my controller I get the following:
NameError in InputsController#index
uninitialized constant InputsController::InputTextVO
#ivo = InputTextVO.new
RubyMine can locate the class and doesn't report any errors in my controller.
You must to add a module if you want to create a subdirectory in the model directory. You can do it like this :
class Wrappers::InputTextVO
...
end
Wrappers::InputTextVO.new #....
It should work.
You can also create a new directory like this app/wrapper.