ActiveType::Object: Be careful when overriding the initialize method

Updated . Posted . Visible to the public.

Background:

ActiveType::Object inherits from ActiveRecod::Base and is designed to behave like an ActiveRecord Object, just without the database persistence.

Don't remove any of the default behavior of the initialize method!

If you have a class which inherits from ActiveType::Object and you need to override the #initialize method, then you should be really careful:

  • Always pass exactly one attribute. ActiveRecod::Base objects really want to get their arguments processable as keyword arguments. Don't change the syntax, or you'll experience pain.
  • Always call super inside of your overridden #initialize method. A lot of magic things happen in the ActiveRecord world. Just let them happen, otherwise kittens will die somewhere. You don't want that.

Example

class Item < ActiveType::Object

  def initialize(attributes)
    super
  
    # Now, as the ActiveRecod::Base part could do it's duty, I can freely do whatever I want.
  end

end

Example pitfall

  • If you don't run the super method inside #initialize, the object is marked as frozen. Rspec mocks (e.g. using partial doubles with receive(partial_double).to ...) in tests would raise the following error (just imagine how hard debugging can be):
ArgumentError:
       Cannot proxy frozen objects, rspec-mocks relies on proxies for method stubbing and expectations.
  • If you define initialize with no argument and don't call super, initialize might be hit with this error:
ArgumentError: 
       Wrong number of arguments (given 1, expected 0)

Further readings

Jakob Scholz
Last edit
Jonas Schiele
License
Source code in this card is licensed under the MIT License.
Posted by Jakob Scholz to makandra dev (2022-10-18 13:29)