多くのフレームワークでは、モデルというのはデータベースとの ORM で使われる単語ですが、Volt のモデルのコンセプトはそれとは少し異なっています。Volt において、モデルはデータを簡単に保存しておくために利用できるクラスを指します。モデルは "Volt::Persistor" を使って生成することもできます。これは、(データベースやローカルストレージ、URL パラメータなどに) データを永続化するための役割を持ちます。Persistor を使わずにモデルを生成した場合は、単純にクラスのインスタンスにデータを保持します。どのようにモデルを使うのか、まず見てみましょう。
モデルは Volt::Model のインスタンスです。まず、インスタンスを直接生成してみましょう。
item = Volt::Model.new
item
# <Volt::Model {:id=>"beb492e2997ebd1365d3bf83"}>
Volt のモデルには ID 属性として自動的に GUID が割り当てられます。モデルは、set/get プロパティを利用できるハッシュのようなものです。モデルのプロパティを扱う方法は2つあります。
First lets look at underscore accessors. これは、明示的に事前に設定しておかなくても set/get プロパティを利用できるものです。
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. アンダースコアをプロパティ名の前につけることで、モデルの set/get プロパティを利用することができます。(※これはハッシュの [:property]
と同様です。詳細は こちら を参照してください)
アンダースコア アクセサは、実際に必要なフィールドを決定する前のプロトタイピングに利用することが多いです。
クラスでフィールドを利用するには、モデルクラスを作成します。モデルクラスは Volt::Model を継承して、app/{コンポーネント}/models/model_name.rb に配置される必要があります。(※もし Volt を使うの初めてであれば、コンポーネントには「main」を指定してください) 新しいモデルを作るには以下のようにします:
bundle exec volt generate model Item
モデルクラスを作成したら、アンダースコア アクセサの代わりに、明示的にフィールドを設定することができます。
class Post < Volt::Model
field :title # 型制約なし
field :body, String # string
field :published, Volt::Boolean # true または false
field :count_or_details, [String, Fixnum] # String または Fixnum
field :notes, String, allow_nil: true # nil を許容する String フィールド
end
フィールドには、オプションで1つ以上の制約を設定することが可能です。もし代入される値が制約された型ではない場合 (そして、string -> int/float のように簡単にキャスト可能なものではない場合)、モデルはバリデーションエラーを発生させtます。注意: Ruby には Boolean クラスが存在せず、Opal には TrueClass/FalseClass がありません。したがって、型制約で真偽値を指定したい場合には Volt::Boolean
を使用してください。
フィールドを追加したら、モデルのインスタンスでプロパティ名のメソッドを実行することで read/assign が可能です (Ruby の getter)。プロパティは「プロパティ名 =」メソッドでセットできます。
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
Volt のモデルはそれ自体では永続化機能が組み込まれていません。永続化を利用するためにはコレクションを利用する必要があります。Volt はデフォルトで多くのコレクションを組み込んでいます。その1つが page
です。コンソール (またはコントローラー) で page
を使うと、page コレクションへアクセスすることができます。
page._name = 'Ryan'
page._name
# => 'Ryan'
コレクションはモデルのための永続化機能を持った根っこのモデルを提供します。「アンダースコア・メソッド」を実行した時は、属性が定義されていればその属性の値を、定義されていなければnil
を返します。
モデルはネストすることも可能です。
page._setting = {}
page._setting._color = 'blue'
page._setting._color
# => 'blue'
空のハッシュをプロパティにアサインして、page
の setting
プロパティでアクセス可能な別のモデルを作っています。setting
モデルは自身のプロパティを持つことができます。
プロパティにモデルをアサインせずにモデルをネストしたい場合は、!
(bang と発音します) メソッドが利用できます。
page._setting!._color = 'blue'
page._setting._color
# => 'blue'
page
# => <PageRoot {:id=>"0df58b9f8b6b6f3404ea4d7b", :setting=><Volt::Model {:id=>"5ea3193e429c1f2ecba21bc5", :color=>"blue"}>}>
._setting!
は、プロパティがアサインされていなければ新しいモデルを作成して返します。(※これを "拡張 (expanding)" と呼びます )
Volt のモデルでは、複数形の名前を持ったプロパティは Volt::ArrayModel
のインスタンスを返します。ArrayModel は通常のアレイと同じように振る舞います。要素の追加/削除は通常のアレイと同様のメソッド (#<<
, 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"}>