palkan/store_attribute

Default value questions v0.8x -> v1.x

Closed this issue · 1 comments

Not a specific issue, just looking to clarify why default values work like they do. Following along with #6 and #7 it looks like it should follow the Attribute API but things seem to have changed in v1.x...

Given:

class User < ActiveRecord::Base
  store_attribute :preferences, :color, :string, default: 'red'
end
INSERT INTO "users" ("id", "preferences") VALUES (1, '{}');

v0.8.1:

User.new.color => "red"
User.new.preferences => {"color"=>"red"}
User.first.color => "red"
User.first.preferences => {"color"=>"red"}

v1.0.2

User.new.color => "red"
User.new.preferences => {"color"=>"red"}
User.first.color => nil
User.first.preferences => nil

An example of this in practice is if we add a new store_attribute to an existing persisted object, I'd expect the default to be set on load. Obviously this would cause the object to be marked dirty the first time it's initialized with the new store_attribute (which gets us into all the trouble we had in #23) but at least persisting would update the serialized value so that would only happen once.

Anyway, just looking for where the decision was made and why, it's making upgrading riskier!

it looks like it should follow the Attribute API but things seem to have changed in v1.x

Yeah, it should have followed but it didn't until v1.

The decision made could be explained by the enhanced example:

class User < ActiveRecord::Base
  attribute :role, :string, default: "guest"
  store_attribute :preferences, :color, :string, default: 'red'
end

INSERT INTO "users" ("id", "role", "preferences") VALUES (1, NULL, '{}');

User.new.role => "guest"
User.new.color => "red"
User.new.preferences => {"color"=>"red"}
User.first.role => nil
User.first.color => nil
User.first.preferences => {}

In other words, the default is only set for new records, but not for the records loaded from a database.
Thus, similarly to adding a new column with the default value, when adding a new key with a default to the store, we should perform a data migration. Although, I agree that this limitation minimize the benefits of using schema-less attributes.

Anyway, enforcing Active Model Attributes compatibility, in my opinion, brings more benefits. That doesn't mean we shouldn't think about a workaround. Maybe, a custom API or something on top of the core functionality.