Call private class method from private instance method

First let me try to explain why the code does not work

class MyModel < ActiveRecord::Base

  def self.create_instance
    model = MyModel.new
    # in here, you are not inside of the instance scope, you are outside of the object
    # so calling model.somemething can only access public method of the object.
    model.init_some_dependencies
    ...
  end
  ...

You could bypass private calling of the method with model.send :init_some_dependencies. But I think in this case there is probably better solution.

I would guess that init_some_dependencies probably contain more business / domain logic rather than persistence. That's why I would suggest to pull out this logic into a "Domain Object" (or some call it Service Object). Which is just a plain ruby object that contain domain logic.

This way you could separate persistence logic to ActiveRecord and the domain logic to that class. Hence you will not bloat the ActiveRecord Model. And you get the bonus of testing the domain logic without the need of ActiveRecord. This will make your test faster.

You could create a file say `lib/MyModelDomain.rb'

class MyModelDomain
  attr_accessor :my_model

  def initialize(my_model)
    @my_model = my_model    
  end

  def init_some_dependencies
    my_model.property = 'some value example' 
  end
end

Now you could use this object say something like this

class MyModel < ActiveRecord::Base

  def self.create_instance
    model = MyModel.new
    domain = MyModelDomain.new(model)
    domain.init_some_dependencies
    domain.my_model
  end

  def initialize_instance
    # do some other work
    other_init

    domain = MyModelDomain.new(self)
    domain.init_some_dependencies
  end
end

You might also want to move the initialize_instance if you think it's necessary

Some resource that go deep into this pattern:

  • http://railscasts.com/episodes/398-service-objects
  • https://www.destroyallsoftware.com/screencasts/catalog/extracting-domain-objects

You can use

model = MyModel.new
model.send :init_some_dependencies

to bypass method visibility checks.

Tags:

Oop

Ruby