diff --git a/README.md b/README.md index 4054187..5891e78 100644 --- a/README.md +++ b/README.md @@ -111,7 +111,7 @@ Resulting in: In the controller: ```ruby def create - @supplier = Supplier.new(supplier_params) + @supplier = Supplier.from_value(supplier_params) @supplier.save end @@ -126,6 +126,7 @@ end 1. [Installation](./docs/installation.md) 2. StoreModel::Model API: + * [Instantiation](./docs/installation.md) * [Validations](./docs/validations.md) * [Enums](./docs/enums.md) * [Nested models](./docs/nested_models.md) diff --git a/docs/instantiation.md b/docs/instantiation.md new file mode 100644 index 0000000..b3b9b57 --- /dev/null +++ b/docs/instantiation.md @@ -0,0 +1,52 @@ +## Instantiation + +You can, of course, instantiate a store model object using `new`: +```ruby +class Configuration + include StoreModel::Model + + attribute :model, :string + attribute :color, :string + + validates :color, presence: true +end + +config = Configuration.new(model: "spaceship", color: "red") +``` + +However, the instance will not have all of the behavior that an instance of a store model +"type" would have. For instance, instantiating with `new` will raise errors when unknown +attributes are passed, rather than providing the [Unknown attributes](./unknown_attributes.md) behavior. + +Store model "types" are what are assigned to `attribute` definitions in ActiveModel classes. + +E.g.: +```ruby +class Product < ApplicationRecord + attribute :configuration, Configuration.to_type +end +``` + +If you want to instantiate not just a store model class, but the associated type, you can use +the `from_value` class method: +```ruby +config = Configuration.from_value(model: "spaceship", color: "red", some_other_attribute: "foo") +``` + +Similarly, if you want to instantiate an array of store model objects, you can use `from_values`: +```ruby +configs = Configuration.from_values([ + {model: "spaceship", color: "red", some_other_attribute: "foo"}, + {model: "car", color: "blue", some_other_attribute: "bar"} +]) +``` + +These methods are shorthand for +```ruby +Configuration.to_type.cast_value(value) +``` +and +```ruby +Configuration.to_array_type.cast_value(values) +``` +respectively. diff --git a/lib/store_model/model.rb b/lib/store_model/model.rb index cd082a2..d3081ca 100644 --- a/lib/store_model/model.rb +++ b/lib/store_model/model.rb @@ -19,6 +19,19 @@ def self.included(base) # :nodoc: base.extend StoreModel::TypeBuilders base.attribute_method_suffix "?" + + base.extend(ClassMethods) + end + + # Class methods for StoreModel::Model + module ClassMethods + def from_value(value) + to_type.cast_value(value) + end + + def from_values(values) + to_array_type.cast_value(values) + end end attr_accessor :parent diff --git a/spec/store_model/model_spec.rb b/spec/store_model/model_spec.rb index 19a726d..227fa4b 100644 --- a/spec/store_model/model_spec.rb +++ b/spec/store_model/model_spec.rb @@ -14,6 +14,24 @@ } end + describe ".from_value" do + context "when unknown attributes are provided" do + it "adds unknown attributes" do + config = Configuration.from_value(attributes.merge(foo: "bar")) + expect(config.unknown_attributes).to include("foo" => "bar") + end + end + end + + describe ".from_values" do + context "when unknown attributes are provided" do + it "adds unknown attributes" do + config = Configuration.from_values([attributes.merge(foo: "bar")]) + expect(config[0].unknown_attributes).to include("foo" => "bar") + end + end + end + describe "#initialize" do context "when symbolized hash is passed" do subject { Configuration.new(attributes) }