Volt's concept of a model is slightly different from many frameworks where a model is the name for the ORM to the database. In Volt, a model is a class where you can store data easily. Models can optionally be created with a "Volt::Persistor", which is responsible for persisting data (to a database, local store, url parameters, etc..) Models created without a persistor simply store the data in the class's instance. Lets first see how to use a model.
A model is simply an instance of Volt::Model. To start, lets create an instance directly.
item = Volt::Model.new
item
# <Volt::Model {:id=>"beb492e2997ebd1365d3bf83"}>
Volt models are automatically assigned a GUID for the id attribute. Models are similar to hashes in that you can get/set properties on them. There are two ways to handle working with properties on Models.
First lets look at underscore accessors. These let you get or set any property without explicitely setting it up ahead of time.
item = Volt::Model.new
item._name = 'Ryan'
item._name
# => "Ryan"
item
# => <Volt::Model {:id=>"d8872b283c6dc1a7861e9baa", :name=>"Ryan"}>
Notice that we didn't have to setup the field name ahead of time. Using an underscore before any property name lets you set/get a property on the model. (Note this is similar to doing [:property]
on a hash. See here for more info.)
Underscore accessors are often used for prototying, before you decide on exactly what fields will be used.
Once you know the fields you will want on a model, you can create a model class to set up fields on the class. A model class inherits from Volt::Model and should be put in app/{component}/models/model_name.rb (If you are new to Volt, use 'main' as the component.) You can generate a new model with the following:
bundle exec volt generate model Item
Once you have a model class you can specify fields on the model explicitly instead of using the underscore accessors.
class Post < Volt::Model
field :title # no type restriction
field :body, String # a string
field :published, Volt::Boolean # true or false
field :count_or_details, [String, Fixnum] # can be String or Fixnum
field :notes, String, allow_nil: true # a String field that can also be nil
end
Fields can optionally take on or more restrictions. If the assigned value is not of the type (and can not be easily cast to the type, e.g. string -> int/float), the model will have a type validation error. NOTE: Ruby does not have a Boolean class, and opal does not have TrueClass/FalseClass, so to specify a boolean, use Volt::Boolean
as the type restriction.
Once you add fields, they can be read and assigned by calling a method with the property name on the model instance (a ruby getter). You can set the property with an property name = method:
new_post = Post.new(body: 'it was the best of times')
new_post.title = 'A Title'
new_post.title
# => 'A Title'
store._posts << new_post
Because Volt Models do not have built-in persistence, you can access them through a collection which sets up the persistence for you. Volt comes with many built-in collections; one is called page
. If you call page
in the console (or a controller), you will get access to the page collection.
page._name = 'Ryan'
page._name
# => 'Ryan'
Collections simply return a root model with the persistence setup for the model. When calling an underscore method, we either get back the attribute value, or nil
if the value isn't defined.
You can also nest models.
page._setting = {}
page._setting._color = 'blue'
page._setting._color
# => 'blue'
Assigning an empty hash to a property creates another model that gets assigned to the setting
property on page
. The setting
model can then be assigned it's own properties.
If you want to nest without needing to assign a model directly to a property, you can use a !
(pronounced bang) method.
page._setting!._color = 'blue'
page._setting._color
# => 'blue'
page
# => <PageRoot {:id=>"0df58b9f8b6b6f3404ea4d7b", :setting=><Volt::Model {:id=>"5ea3193e429c1f2ecba21bc5", :color=>"blue"}>}>
Calling ._setting!
creates a model if the property is not assigned and returns the new model. (This is called "expanding")
In Volt models, plural properties return a Volt::ArrayModel
instance. ArrayModels behave the same way as normal arrays. You can add/remove items to the array with normal array methods like #<<
, push
, append
, delete
, delete_at
, etc.
page._items
# #<Volt::ArrayModel []>
page._items << {name: 'Item 1'}
page._items
# #<Volt::ArrayModel [<Volt::Model {:id=>"997e8a28c9675452ebcd5fa7", :name=>"Item 1"}>]>
page._items.size
# => 1
page._items[0]
# => <Volt::Model {:id=>"997e8a28c9675452ebcd5fa7", :name=>"Item 1"}>