I have these models:
Class A
embeds_many :b
end
Class B
belongs_to :c
end
Class C
end
I'm working with rails_admin and mongoid. In admin, when I try to retrieve the list of C records when I'm creating an A instance I'm getting this error:
This only happens on production envirnment not in development
NoMethodError (undefined method `associations' for nil:NilClass):
/home/pablo/.rvm/gems/ruby-2.3.0#mh-backend/bundler/gems/rails_admin-355dc80f8a20/lib/rails_admin/adapters/mongoid/abstract_object.rb:10:in `initialize'
/home/pablo/.rvm/gems/ruby-2.3.0#mh-backend/bundler/gems/rails_admin-355dc80f8a20/lib/rails_admin/adapters/mongoid.rb:24:in `new'
/home/pablo/.rvm/gems/ruby-2.3.0#mh-backend/bundler/gems/rails_admin-355dc80f8a20/lib/rails_admin/adapters/mongoid.rb:24:in `get'
/home/pablo/.rvm/gems/ruby-2.3.0#mh-backend/bundler/gems/rails_admin-355dc80f8a20/app/controllers/rails_admin/main_controller.rb:138:in `get_association_scope_from_params'
Taking a look at rails_admin code we can see that piece of code in mongoid.rb file.
def get(id)
AbstractObject.new(model.find(id))
rescue => e
raise e if %w(
Mongoid::Errors::DocumentNotFound
Mongoid::Errors::InvalidFind
Moped::Errors::InvalidObjectId
BSON::InvalidObjectId
).exclude?(e.class.to_s)
end
If we pay attention at this code we can see that model.find(id) must produce a Mongoid::Errors::DocumentNotFound if document doesn't exists by default.
However, in mongoid you can avoid the raise of this error with raise_not_found_error: true in mongo config file, this produce the undefined method of nil class.
Tracking issue on github
Related
I am in the process of upgrading a ~2 year old Rails app from 6.1 to 7.0.1
I have an STI setup where Pursuit is the main class and it has several other types as descendants:
# app/models/pursuit.rb
require 'sti_preload'
class Pursuit < ApplicationRecord
# ...
end
Descendant classes all look like this:
# app/models/pur_issue.rb
class PurIssue < Pursuit
# ...
end
--
# app/models/pur_goal.rb
class PurGoal < Pursuit
# ...
end
--
# app/models/pur_tracker.rb
class PurTracker < Pursuit
# ...
end
I have been using STI preload snippet as recommended by the Ruby Guides, and all worked well under Rails 6.0 and 6.1.
But now that I am upgrading to Rails 7.0.1, I suddenly get an "Uninitialized Constant" error for only the PurIssue subclass whereas all the other subclasses load fine:
Showing /Users/me/gits/rffvp/app/views/pursuits/_stats.html.slim where line #1 raised:
uninitialized constant PurIssue
Extracted source (around line #33):
33 types_in_db.each do |type|
34 logger.debug("Preloading STI type #{type}")
35 type.constantize
36 end
37 logger.debug("Types in database #{types_in_db}")
Trace of template inclusion: #<ActionView::Template app/views/layouts/_footer.html.slim locals=[]>, #<ActionView::Template app/views/layouts/application.html.slim locals=[]>
Rails.root: /Users/me/gits/rffvp
Application Trace | Framework Trace | Full Trace
lib/sti_preload.rb:33:in `block in preload_sti'
lib/sti_preload.rb:31:in `each'
lib/sti_preload.rb:31:in `preload_sti'
lib/sti_preload.rb:13:in `descendants'
app/models/pursuit.rb:71:in `<class:Pursuit>'
app/models/pursuit.rb:54:in `<main>'
app/models/pur_issue.rb:52:in `<main>'
app/views/pursuits/_stats.html.slim:1
app/views/layouts/_footer.html.slim:14
app/views/layouts/application.html.slim:13
I can't seem to figure out why PurIssue will not load anymore whereas all the other subclasses will. This is breaking my entire app since PurIssues are the most important data points.
Can someone point me to a Rails configuration change between 6.0, 6.1 and 7.0 that might cause this different behavior?
# lib/sti_preload.rb
module StiPreload
unless Rails.application.config.eager_load
extend ActiveSupport::Concern
included do
cattr_accessor :preloaded, instance_accessor: false
end
class_methods do
def descendants
preload_sti unless preloaded
super
end
# Constantizes all types present in the database. There might be more on
# disk, but that does not matter in practice as far as the STI API is
# concerned.
#
# Assumes store_full_sti_class is true, the default.
def preload_sti
types_in_db = \
base_class
.unscoped
.select(inheritance_column)
.distinct
.pluck(inheritance_column)
.compact
types_in_db.each do |type|
logger.debug("Preloading STI type #{type}")
type.constantize
end
logger.debug("Types in database #{types_in_db}")
self.preloaded = true
end
end
end
end
Zeitwerk shows the same error by the way:
$ rails zeitwerk:check
Hold on, I am eager loading the application.
rails aborted!
NameError: uninitialized constant PurIssue
/Users/me/gits/rffvp/lib/sti_preload.rb:33:in `block in preload_sti'
/Users/me/gits/rffvp/lib/sti_preload.rb:31:in `each'
/Users/me/gits/rffvp/lib/sti_preload.rb:31:in `preload_sti'
/Users/me/gits/rffvp/lib/sti_preload.rb:13:in `descendants'
/Users/me/gits/rffvp/app/models/concerns/validateable.rb:10:in `block in <module:Validateable>'
/Users/me/gits/rffvp/app/models/pursuit.rb:68:in `include'
/Users/me/gits/rffvp/app/models/pursuit.rb:68:in `<class:Pursuit>'
/Users/me/gits/rffvp/app/models/pursuit.rb:54:in `<main>'
/Users/me/gits/rffvp/app/models/pur_issue.rb:1:in `<main>'
Tasks: TOP => zeitwerk:check
(See full trace by running task with --trace)
I saw the same thing trying to do an upgrade to rails 7. I believe it originates with this change: https://github.com/rails/rails/commit/ffae3bd8d69f9ed1ae185e960d7a38ec17118a4d
Effectively the change to invoke Class.descendants directly in the internal association callback methods exposes a more longstanding implicit issue with invoking Class.descendants at all during the autoload, as the StiPreload implementation may result in a problem where it circularly attempts to constantize the original class being autoloaded. I've added an issue in the Rails repo here https://github.com/rails/rails/issues/44252
Say I have:
app/models/food/fruit.rb:
module Food
class Fruit
class_attribute :field_mapping
self.field_mapping = MyOrg::Trees::Details.field_mapping
# other things including:
end
end
In local/development mode, I can open a console and do/get this:
rails console
[1] pry(main)> Food::Fruit
NameError: uninitialized constant MyOrg::Trees::Details
MyOrg::Trees::Details will eventually be defined via a gem, but until then I want to fake it by adding the following to the top of the same file; why isn't this doing the trick?
module MyOrg
module Trees
class Details
def field_mapping
end
end
end
end
Note: when I paste the above into a local/development console, I can then successfully do this:
[2] pry(main)> MyOrg::Trees::Details.new.field_mapping
=> nil
When I added the above fake, I accidentally started trying to reference it to test what I was doing...
rails console
[1] pry(main)> MyOrg::Trees::Details
NameError: uninitialized constant MyOrg::Trees::Details
...but I should have called Food::Fruit as before, and I would have isolated the issue...
rails console
[1] pry(main)> Food::Fruit
NoMethodError: undefined method `field_mapping' for MyOrg::Trees::Details:Class
...ah, I need to make it a class method...
module MyOrg
module Trees
class Details
def self.field_mapping
end
end
end
end
...and then...
rails console
[1] pry(main)> Food::Fruit
NoMethodError: undefined method `values' for nil:NilClass
So, I appeased the undefined method error, and now have a new problem, which is that further down the original code there is actually another reference to field_mapping (field_mapping.values) which now has to be appeased...
module MyOrg
module Trees
class Details
def self.field_mapping
{}
end
end
end
end
...and now...
rails console
[1] pry(main)> Food::Fruit
=> Food::Fruit
I am using Rails 3.2.0.
I have a simple model as show below
class Favorite < ActiveRecord::Base
validates :lst, :presence => true
validates :uuid, :presence => true, :uniqueness => {:scope => :lst}
end
If I try this
f = Favorite.new
f.valid?
I get the following error message:
NoMethodError: undefined method `zero?' for nil:NilClass
from /Users/ragrawal/.rvm/gems/ruby-1.9.2-p290/gems/activerecord-3.2.0/lib/active_record/associations/alias_tracker.rb:28:in `aliased_name_for'
from /Users/ragrawal/.rvm/gems/ruby-1.9.2-p290/gems/activerecord-3.2.0/lib/active_record/associations/join_dependency.rb:17:in `initialize'
from /Users/ragrawal/.rvm/gems/ruby-1.9.2-p290/gems/activerecord-3.2.0/lib/active_record/relation/finder_methods.rb:219:in `new'
from /Users/ragrawal/.rvm/gems/ruby-1.9.2-p290/gems/activerecord-3.2.0/lib/active_record/relation/finder_methods.rb:219:in `construct_join_dependency_for_association_find'
from /Users/ragrawal/.rvm/gems/ruby-1.9.2-p290/gems/activerecord-3.2.0/lib/active_record/relation/finder_methods.rb:192:in `exists?'
from /Users/ragrawal/.rvm/gems/ruby-1.9.2-p290/gems/activerecord-3.2.0/lib/active_record/validations/uniqueness.rb:32:in `validate_each'
from /Users/ragrawal/.rvm/gems/ruby-1.9.2-p290/gems/activemodel-3.2.0/lib/active_model/validator.rb:153:in `block in validate'
from /Users/ragrawal/.rvm/gems/ruby-1.9.2-p290/gems/activemodel-3.2.0/lib/active_model/validator.rb:150:in `each'
from /Users/ragrawal/.rvm/gems/ruby-1.9.2-p290/gems/activemodel-3.2.0/lib/active_model/validator.rb:150:in `validate'
from /Users/ragrawal/.rvm/gems/ruby-1.9.2-p290/gems/activesupport-3.2.0/lib/active_support/callbacks.rb:310:in `_callback_before_15'
from /Users/ragrawal/.rvm/gems/ruby-1.9.2-p290/gems/activesupport-3.2.0/lib/active_support/callbacks.rb:429:in `_run__1275595979440079611__validate__42615372200132002__callbacks'
from /Users/ragrawal/.rvm/gems/ruby-1.9.2-p290/gems/activesupport-3.2.0/lib/active_support/callbacks.rb:405:in `__run_callback'
from /Users/ragrawal/.rvm/gems/ruby-1.9.2-p290/gems/activesupport-3.2.0/lib/active_support/callbacks.rb:385:in `_run_validate_callbacks'
from /Users/ragrawal/.rvm/gems/ruby-1.9.2-p290/gems/activesupport-3.2.0/lib/active_support/callbacks.rb:81:in `run_callbacks'
from /Users/ragrawal/.rvm/gems/ruby-1.9.2-p290/gems/activemodel-3.2.0/lib/active_model/validations.rb:212:in `run_validations!'
from /Users/ragrawal/.rvm/gems/ruby-1.9.2-p290/gems/activemodel-3.2.0/lib/active_model/validations/callbacks.rb:53:in `block in run_validations!'
....
....
ActiveRecord AREL table aliasing is breaking
The error is likely due to ActiveRecord AREL losing track of how to sum an empty array.
The relevant line of code is in the file alias_tracker.rb:
count.sum
If count is an empty array then the line evaluates as:
[].sum
In Ruby that fails:
$ irb
> [].sum
NoMethodError: undefined method `sum' for []:Array
Rails ActiveSupport Enumerable#sum
In Rails that succeeds because ActiveSupport is creating Enumerable#sum
$ irb
> require 'active_support/core_ext/enumerable'
> [].sum
=> 0
Your problem is likely that some unrelated area of your app is also creating Enumerable#sum or Array#sum. The unrelated code is overwriting the Rails method.
The could be happening in your code or in an unrelated gem. The Rails gem loads early, typically first in your Gemfile, and any later gem can interfere with Rails.
How to fix it?
Have you written a method named sum, perhaps within a module named Enumerable or Array? If so, that's a good place to start. You could rename your method, or you could try changing your method to match the Rails method by replacing your #sum code with this code:
module Enumerable
def sum(identity = 0, &block)
if block_given?
map(&block).sum(identity)
else
inject(:+) || identity
end
end
end
If you haven't written a method named sum in your code, then the conflict is likely in a gem you're using. Try commenting-out gems that you're using then reload your app.
You can search for a gem that defines a method named sum like this:
$ cd /usr/lib/ruby/gems
$ find | xargs grep "def sum\b"
Are you using any gems named sixarm? If so, contact me and I'll fix them for you. These are by me, and a few of them do define #sum for use with statistics tools and utilties.
Hope this helps. Can you post here if it solves your issue?
Here is the code
#add email of team lead of the current user
def add_the_tl_email(to_address, session_user_id)
ul = UserLevel.find_by_user_id(session_user_id)
if !ul.team.nil? && !ul.role.nil?
User.user_status('active').joins(:user_levels).where(:user_levels => {:position => 'tl',
:role => ul.role,
:team => ul.team }).each do
|u| to_address << u.email
end
end
end
The error from spec:
1) CustomersController GET customer page 'create' successful should create one customer record
Failure/Error: post 'create', :customer => #customer
NoMethodError:
undefined method `team' for nil:NilClass
# ./app/mailers/user_mailer.rb:36:in `add_the_tl_email'
# ./app/mailers/user_mailer.rb:15:in `notify_tl_dh_ch_ceo'
# ./app/controllers/customers_controller.rb:27:in `create'
# ./spec/controllers/customers_controller_spec.rb:48:in `block (5 levels) in <top (required)>'
# ./spec/controllers/customers_controller_spec.rb:47:in `block (4 levels) in <top (required)>'
team is a field in user_level. Here is the user_level in factory:
Factory.define :user_level do |level|
level.role "sales"
level.position "member"
level.team 1
level.association :user
end
In rails console, the ul.team.nil? returns either true or false on test data generated by factory.
Since team is a field in user_level, why there is error in spec like: NoMethodError:
undefined method `team' for nil:NilClass ?
Thanks.
The issues is that nil.team is not a method*
NoMethodError:
undefined method `team' for nil:NilClass
That is, ul evaluates to nil: check ul.nil? before checking ul.team.nil?... but might want to find out why the find failing to start with ;-)
Happy coding.
*This is what the real error message says, the title of the post is garbage :-/
The call in
ul = UserLevel.find_by_user_id(session_user_id)
returned nil and thus nil was assigned to ul.
So when you called
!ul.team.nil?
Ruby tried to call team on nil. nil is an instance of NilClass and there is no method named team on NilClass.
I know this has to be something stupid, but I keep getting the following error in one of my examples:
undefined method `new' for #<Class:0x211d274>
I have created a simple example to show the error:
describe LateCharge do
before :each do
#membership = Membership.new
#location = mock_model(Location, :late_payment_rate => 10)
end
it "should initialize" do
LateCharge.respond_to?('new').should == true
#charge = LateCharge.new(#membership, #location)
end
end
The strange part is, when I run the example by itself, it passes. When I run it with all my examples, it fails with the following error:
NoMethodError in 'LateCharge should initialize'
undefined method `new' for #<Class:0x211d274>
/Library/Ruby/Gems/1.8/gems/activerecord-2.3.2/lib/active_record/base.rb:1964:in `method_missing_without_paginate'
/Users/l33/.gem/ruby/1.8/gems/mislav-will_paginate-2.3.11/lib/will_paginate/finder.rb:170:in `method_missing'
./spec/models/late_charge_spec.rb:15:
It is failing on the line: #charge = LateCharge.new(#membership, #location)
I do not have any problems instantiating the LateCharge object at run time or from the console.
Anyone have any ideas?
Seems to me the following information is key to your issue:
will_paginate/finder.rb:170:in `method_missing'
Hey Lee - not sure if you're still having this problem, but I had the exact same thing and it's because another spec I had was unstubbing the function.