2

My classes are as follows, with Customer inheriting from User using the single-table inheritance approach. User has attributes name and email while Order has destination.

class User < ActiveRecord::Base
end

class Customer < User
  has_many :orders
end

class Order < ActiveRecord::Base
  belongs_to :customer
end

Based on the following snippet of code run using the Rails console

c = Customer.create
c.orders << Order.create
c.orders.delete_all

Executing the delete_all function in the last line results in NoMethodError: undefined method 'name' for nil:NilClass. However, the following works.

c = Customer.new
c.orders << Order.create
c.orders.delete_all

The same works perfectly find on a friend's computer. Anyone have any idea what might be going on? Might it be related to a bug in the version of something I'm using?

Stack trace

NoMethodError: undefined method `name' for nil:NilClass
from /home/leo/.rvm/gems/ruby-2.2.1/gems/activerecord-    4.0.3/lib/active_record/associations/has_many_association.rb:81:in `cached_counter_attribute_name'
from /home/leo/.rvm/gems/ruby-2.2.1/gems/activerecord-4.0.3/lib/active_record/associations/has_many_association.rb:77:in `has_cached_counter?'
from /home/leo/.rvm/gems/ruby-2.2.1/gems/activerecord-4.0.3/lib/active_record/associations/has_many_association.rb:85:in `update_counter'
from /home/leo/.rvm/gems/ruby-2.2.1/gems/activerecord-4.0.3/lib/active_record/associations/has_many_association.rb:125:in `delete_records'
from /home/leo/.rvm/gems/ruby-2.2.1/gems/activerecord-4.0.3/lib/active_record/associations/collection_association.rb:493:in `remove_records'
from /home/leo/.rvm/gems/ruby-2.2.1/gems/activerecord-4.0.3/lib/active_record/associations/collection_association.rb:486:in `block in delete_or_destroy'
from /home/leo/.rvm/gems/ruby-2.2.1/gems/activerecord-4.0.3/lib/active_record/associations/collection_association.rb:152:in `block in transaction'
from /home/leo/.rvm/gems/ruby-2.2.1/gems/activerecord-4.0.3/lib/active_record/connection_adapters/abstract/database_statements.rb:202:in `block in transaction'
from /home/leo/.rvm/gems/ruby-2.2.1/gems/activerecord-4.0.3/lib/active_record/connection_adapters/abstract/database_statements.rb:210:in `within_new_transaction'
from /home/leo/.rvm/gems/ruby-2.2.1/gems/activerecord-4.0.3/lib/active_record/connection_adapters/abstract/database_statements.rb:202:in `transaction'
from /home/leo/.rvm/gems/ruby-2.2.1/gems/activerecord-4.0.3/lib/active_record/transactions.rb:209:in `transaction'
from /home/leo/.rvm/gems/ruby-2.2.1/gems/activerecord-4.0.3/lib/active_record/associations/collection_association.rb:151:in `transaction'
from /home/leo/.rvm/gems/ruby-2.2.1/gems/activerecord-4.0.3/lib/active_record/associations/collection_association.rb:486:in `delete_or_destroy'
from /home/leo/.rvm/gems/ruby-2.2.1/gems/activerecord-4.0.3/lib/active_record/associations/collection_association.rb:230:in `delete'
from /home/leo/.rvm/gems/ruby-2.2.1/gems/activerecord-4.0.3/lib/active_record/associations/collection_association.rb:160:in `delete_all'
from /home/leo/.rvm/gems/ruby-2.2.1/gems/activerecord-4.0.3/lib/active_record/associations/collection_proxy.rb:422:in `delete_all'
from (irb):6
from /home/leo/.rvm/gems/ruby-2.2.1/gems/railties-4.0.3/lib/rails/commands/console.rb:90:in `start'
from /home/leo/.rvm/gems/ruby-2.2.1/gems/railties-4.0.3/lib/rails/commands/console.rb:9:in `start'
from /home/leo/.rvm/gems/ruby-2.2.1/gems/railties-4.0.3/lib/rails/commands.rb:62:in `<top (required)>'
from bin/rails:4:in `require'
from bin/rails:4:in `<main>'
keylime
  • 23
  • 4
  • Can you precise to which model `name` is an attributes ? It looks like the error doesn't come from the delete_all method – Chambeur Apr 02 '15 at 09:29
  • 1
    Can you give a stack trace of the exception and the full source of User, Customer and Order. There seems to be some active record callback or validation issue. The difference between `new` and `create` is that `create` immediately runs all callbacks, validations and saves the object in database, whereas `new` only creates the object in memory. – Oleg K. Apr 02 '15 at 09:42
  • @Chambeur I did specify it above, but perhaps I wasn't clear enough. User fields => name, email Order fields => destination – keylime Apr 02 '15 at 10:29
  • @OlegK. The full source code is almost exactly the same; the only things I did not write in the above are functions to check the state of the object. There are no self-written callbacks in the full source either. – keylime Apr 02 '15 at 10:37
  • @keylime it crashes in `has_many_association.rb::cached_counter_attribute_name`, so there seems to be some cached counter on customer's `orders` and there's something wrong with the counter. It works for `new` record because it does not perform that callbacks unless the record is saved in DB. Can you find the `orders` counter in the source? it should look line `has_many :orders, counter_cache: :true` – Oleg K. Apr 02 '15 at 10:47
  • @OlegK. Thanks for your suggestion, but since the I have discovered that problem is indeed one to do with the Ruby version, I will simply downgrade for now. Even if I do find the source of the problem, it will likely take a lot of effort to fix it. – keylime Apr 02 '15 at 13:41

5 Answers5

3

I guess you were right about the problem about the ruby version. I found this question.

The guy had a similar problem and he fixed it by switching his ruby version from ruby-2.2.0 to ruby-2.1.1.

If it's not the ruby version, it could be the ActiveRecord Version.

Community
  • 1
  • 1
Chambeur
  • 1,509
  • 1
  • 12
  • 16
  • True enough, it was the Ruby version. My friend's computer was running 2.1.5 so I tried downgrading to that and it works find now. Thank you. – keylime Apr 02 '15 at 13:42
  • Another option of course is to up your rails version in the Gemfile. I tried switching my reference to rails to gem 'rails', '4.2.3' and ran bundle update and that fixed the problem – Kalman Mar 31 '16 at 16:16
  • 1
    For those using 4.1, I upgraded to 4.1.16 and it fixed the issue – The Lazy Log Nov 21 '16 at 01:03
3

This is the Rails issue with Ruby 2.2.2: https://github.com/rails/rails/issues/18991 . It's closed and fixed in 3.2.22).

juanignaciosl
  • 3,435
  • 2
  • 28
  • 28
1

Try updating you Customer class association with

has_many :orders, :dependent => :destroy

or

has_many :orders, :dependent => :delete_all

Depending on what you want to achieve.

:destroy causes all the associated objects to also be destroyed.

:delete_all causes all the associated objects to be deleted directly from the database without executing callbacks.

Thomas
  • 622
  • 5
  • 13
0

for delete_all

for example

 Post.delete_all("person_id = 5 AND (category = 'Something' OR category = 'Else')")
  Post.delete_all(["person_id = ? AND (category = ? OR category = ?)", 5, 'Something', 'Else'])

for destroy_all

for example

 Person.destroy_all("last_login < '2004-04-04'")
  Person.destroy_all(:status => "inactive")
Milind
  • 4,535
  • 2
  • 26
  • 58
0

It seems you have no inverse associations and Rails fails to resolve the order's customer when updating the cached counters. Try this:

class Customer < User
  has_many :orders, inverse_of: :customer
end

class Order < ActiveRecord::Base
  belongs_to :customer, inverse_of: :orders
end
Oleg K.
  • 1,549
  • 8
  • 11