taxjar-ruby icon indicating copy to clipboard operation
taxjar-ruby copied to clipboard

Taxjar::Base has confusing mixed data states

Open mintyfresh opened this issue 2 years ago • 0 comments

Taxjar::Base and all the data models that currently inherit from it use a confusing mix of data states, stored both directly into an @attrs instance variable, and also managed by ModelAttributes (which stores each attribute in its own instance variable).

While these states are initially in-sync when the object is constructed, using any of the attribute writers causes these states to go out of sync, and data read from the attributes to no longer match the data to be sent in an API request.

Expected Behaviour

order = Taxjar::Order.new(to_city: 'Toronto')
assert_equal order.to_city, 'Toronto' # Passes
assert_equal order.to_hash['to_city'], 'Toronto' # Passes

order.to_city = 'New York'
assert_equal order.to_city, 'New York' # Passes
assert_equal order.to_hash['to_city'], 'New York' # Passes

assert_equal order.to_json, '{"to_city":"New York"}' # Passes

Actual Behaviour

order = Taxjar::Order.new(to_city: 'Toronto')
assert_equal order.to_city, 'Toronto' # Passes
assert_equal order.to_hash['to_city'], 'Toronto' # Passes

order.to_city = 'New York'
assert_equal order.to_city, 'New York' # Passes
assert_equal order.to_hash['to_city'], 'New York' # Fails! `@attrs['to_city']` is still equal to 'Toronto'!

assert_equal order.to_json, '{"to_city":"New York"}' # Fails! `#to_json` still returns `{"to_city":"Toronto"}`!

This is caused because Taxjar::Base stores two separate data states:

  • @attrs, which is only assigned in the constructor, and delegates #to_hash
  • ModelAttributes, which is initialized in the constructor, and whenever attribute writers are used, but never updates @attrs state

Another Example

order = Taxjar::Order.new

order.to_country = 'CA'
order.to_state = 'ON'
order.to_city = 'Toronto'

order.to_json # => "{}" - Empty JSON object!

This happens because Taxjar::Base#to_h and Taxjar::Base#to_hash delegate to @attrs, which is not updated by attribute writers.

Suggested Fix

All usage of @attrs should be removed, instead using the #attributes method provided by ModelAttributes.

mintyfresh avatar Jul 06 '22 18:07 mintyfresh