1

I've got a callback and method defined in the parent class of a Rails STI setup.

class Parent < ActiveRecord::Base
  before_save :populate_name

  # implicitly public
  def populate_name
    self.name = "foobar"
  end

class Child < Parent
end

When I make populate_name private or protected like this:

class Parent < ActiveRecord::Base
  before_save :populate_name

  private
  def populate_name
    self.name = "foobar"
  end

class Child < Parent
end

Then I get this error:

NameError - undefined local variable or method `populate_name' for #<Child:0x007ff901eace30>:
  activemodel (3.2.16) lib/active_model/attribute_methods.rb:407:in `method_missing'
  activerecord (3.2.16) lib/active_record/attribute_methods.rb:149:in `method_missing'
  activesupport (3.2.16) lib/active_support/callbacks.rb:407:in `_run__3119425560225797910__save__1411052685854526397__callbacks'
  activesupport (3.2.16) lib/active_support/callbacks.rb:405:in `__run_callback'
  activesupport (3.2.16) lib/active_support/callbacks.rb:385:in `_run_save_callbacks'
  activesupport (3.2.16) lib/active_support/callbacks.rb:81:in `run_callbacks'
  activerecord (3.2.16) lib/active_record/callbacks.rb:264:in `create_or_update'
  activerecord (3.2.16) lib/active_record/persistence.rb:84:in `save'
  activerecord (3.2.16) lib/active_record/validations.rb:50:in `save'
  activerecord (3.2.16) lib/active_record/attribute_methods/dirty.rb:22:in `save'
  activerecord (3.2.16) lib/active_record/transactions.rb:259:in `block (2 levels) in save'
  activerecord (3.2.16) lib/active_record/transactions.rb:313:in `block in with_transaction_returning_status'
  activerecord (3.2.16) lib/active_record/connection_adapters/abstract/database_statements.rb:192:in `transaction'
  activerecord (3.2.16) lib/active_record/transactions.rb:208:in `transaction'
  activerecord (3.2.16) lib/active_record/transactions.rb:311:in `with_transaction_returning_status'
  activerecord (3.2.16) lib/active_record/transactions.rb:259:in `block in save'
  activerecord (3.2.16) lib/active_record/transactions.rb:270:in `rollback_active_record_state!'
  activerecord (3.2.16) lib/active_record/transactions.rb:258:in `save'
  app/controllers/child_controller.rb:135:in `create_or_update'

Is public required for the callback?

justingordon
  • 12,553
  • 12
  • 72
  • 116

2 Answers2

2

Private methods can't be accessed by children. Protected methods can. The child doesn't have access to the private method.

When should we consider using private or protected?

Community
  • 1
  • 1
Blaine Hatab
  • 1,626
  • 17
  • 24
0

Keeping this question up in case anybody ever googles this (and it's a fat finger thing).

I had accidently put the private part after the end for the class before the module end. It's easy to just throw the private, then private method before the last end, but one really needs to be careful if there's nesting!

So yes

  1. make the callbacks private
  2. if you don't see something in a google query for something simple, you must have fat fingered something
module Foo
  class Parent < ActiveRecord::Base
    before_save :populate_name
  end

  private

  def populate_name
    self.name = "foobar"
  end
end

class Child < Parent
end

Then I get this error:

NameError - undefined local variable or method `populate_name' for #<Child:0x007ff901eace30>:
  activemodel (3.2.16) lib/active_model/attribute_methods.rb:407:in `method_missing'
  activerecord (3.2.16) lib/active_record/attribute_methods.rb:149:in `method_missing'
  activesupport (3.2.16) lib/active_support/callbacks.rb:407:in `_run__3119425560225797910__save__1411052685854526397__callbacks'
  activesupport (3.2.16) lib/active_support/callbacks.rb:405:in `__run_callback'
  activesupport (3.2.16) lib/active_support/callbacks.rb:385:in `_run_save_callbacks'
  activesupport (3.2.16) lib/active_support/callbacks.rb:81:in `run_callbacks'
  activerecord (3.2.16) lib/active_record/callbacks.rb:264:in `create_or_update'
  activerecord (3.2.16) lib/active_record/persistence.rb:84:in `save'
  activerecord (3.2.16) lib/active_record/validations.rb:50:in `save'
  activerecord (3.2.16) lib/active_record/attribute_methods/dirty.rb:22:in `save'
  activerecord (3.2.16) lib/active_record/transactions.rb:259:in `block (2 levels) in save'
  activerecord (3.2.16) lib/active_record/transactions.rb:313:in `block in with_transaction_returning_status'
  activerecord (3.2.16) lib/active_record/connection_adapters/abstract/database_statements.rb:192:in `transaction'
  activerecord (3.2.16) lib/active_record/transactions.rb:208:in `transaction'
  activerecord (3.2.16) lib/active_record/transactions.rb:311:in `with_transaction_returning_status'
  activerecord (3.2.16) lib/active_record/transactions.rb:259:in `block in save'
  activerecord (3.2.16) lib/active_record/transactions.rb:270:in `rollback_active_record_state!'
  activerecord (3.2.16) lib/active_record/transactions.rb:258:in `save'
  app/controllers/child_controller.rb:135:in `create_or_update'
John Donner
  • 524
  • 6
  • 14
justingordon
  • 12,553
  • 12
  • 72
  • 116