README.md in alba-1.4.0 vs README.md in alba-1.5.0
- old
+ new
@@ -63,13 +63,15 @@
* Conditional attributes and associations
* Selectable backend
* Key transformation
* Root key inference
* Error handling
+* Nil handling
* Resource name inflection based on association name
* Circular associations control
* [Experimental] Types for validation and conversion
+* Layout
* No runtime dependencies
## Anti features
* Sorting keys
@@ -127,11 +129,11 @@
Alba.on_error :ignore
```
For the details, see [Error handling section](#error-handling)
-### Simple serialization with key
+### Simple serialization with root key
```ruby
class User
attr_accessor :id, :name, :email, :created_at, :updated_at
def initialize(id, name, email)
@@ -144,11 +146,11 @@
end
class UserResource
include Alba::Resource
- key :user
+ root_key :user
attributes :id, :name
attribute :name_with_email do |resource|
"#{resource.name}: #{resource.email}"
@@ -241,11 +243,11 @@
### Inline definition with `Alba.serialize`
`Alba.serialize` method is a shortcut to define everything inline.
```ruby
-Alba.serialize(user, key: :foo) do
+Alba.serialize(user, root_key: :foo) do
attributes :id
many :articles do
attributes :title, :body
end
end
@@ -323,11 +325,11 @@
```
You can also transform root key when:
* `Alba.enable_inference!` is called
-* `key!` is called in Resource class
+* `root_key!` is called in Resource class
* `root` option of `transform_keys` is set to true or `Alba.enable_root_key_transformation!` is called.
```ruby
Alba.enable_inference!
@@ -340,11 +342,11 @@
end
class BankAccountResource
include Alba::Resource
- key!
+ root_key!
attributes :account_number
transform_keys :dash, root: true
end
@@ -568,10 +570,99 @@
[key, error.message]
end
end
```
+### Nil handling
+
+Sometimes we want to convert `nil` to different values such as empty string. Alba provides a flexible way to handle `nil`.
+
+```ruby
+class User
+ attr_reader :id, :name, :age
+
+ def initialize(id, name = nil, age = nil)
+ @id = id
+ @name = name
+ @age = age
+ end
+end
+
+class UserResource
+ include Alba::Resource
+
+ on_nil { '' }
+
+ root_key :user, :users
+
+ attributes :id, :name, :age
+end
+
+UserResource.new(User.new(1)).serialize
+# => '{"user":{"id":1,"name":"","age":""}}'
+```
+
+You can get various information via block parameters.
+
+```ruby
+class UserResource
+ include Alba::Resource
+
+ on_nil do |object, key|
+ if key == age
+ 20
+ else
+ "User#{object.id}"
+ end
+ end
+
+ root_key :user, :users
+
+ attributes :id, :name, :age
+end
+
+UserResource.new(User.new(1)).serialize
+# => '{"user":{"id":1,"name":"User1","age":20}}'
+```
+
+You can also set global nil handler.
+
+```ruby
+Alba.on_nil { 'default name' }
+
+class Foo
+ attr_reader :name
+ def initialize(name)
+ @name = name
+ end
+end
+
+class FooResource
+ include Alba::Resource
+
+ key :foo
+
+ attributes :name
+end
+
+FooResource.new(Foo.new).serialize
+# => '{"foo":{"name":"default name"}}'
+
+class FooResource2
+ include Alba::Resource
+
+ key :foo
+
+ on_nil { '' } # This is applied instead of global handler
+
+ attributes :name
+end
+
+FooResource2.new(Foo.new).serialize
+# => '{"foo":{"name":""}}'
+```
+
### Metadata
You can set a metadata with `meta` DSL or `meta` option.
```ruby
@@ -664,9 +755,71 @@
UserResource.new(user).serialize
# => TypeError, 'Attribute bio is expected to be String but actually nil.'
```
Note that this feature is experimental and interfaces are subject to change.
+
+### Layout
+
+Sometimes we'd like to serialize JSON into a template. In other words, we need some structure OUTSIDE OF serialized JSON. IN HTML world, we call it a "layout".
+
+Alba supports serializing JSON in a layout. You need a file for layout and then to specify file with `layout` method.
+
+```erb
+{
+ "header": "my_header",
+ "body": <%= serialized_json %>
+}
+```
+
+```ruby
+class FooResource
+ include Alba::Resource
+ layout file: 'my_layout.json.erb'
+end
+```
+
+Note that layout files are treated as `json` and `erb` and evaluated in a context of the resource, meaning
+
+* A layout file must be a valid JSON
+* You must write `<%= serialized_json %>` in a layout to put serialized JSON string into a layout
+* You can access `params` in a layout so that you can add virtually any objects to a layout
+ * When you access `params`, it's usually a Hash. You can use `encode` method in a layout to convert `params` Hash into a JSON with the backend you use
+* You can also access `object`, the underlying object for the resource
+
+In case you don't want to have a file for layout, Alba lets you define and apply layouts inline:
+
+```ruby
+class FooResource
+ include Alba::Resource
+ layout inline: proc do
+ {
+ header: 'my header',
+ body: serializable_hash
+ }
+ end
+end
+```
+
+In the example above, we specify a Proc which returns a Hash as an inline layout. In the Proc we can use `serializable_hash` method to access a Hash right before serialization.
+
+You can also use a Proc which returns String, not a Hash, for an inline layout.
+
+```ruby
+class FooResource
+ include Alba::Resource
+ layout inline: proc do
+ %({
+ "header": "my header",
+ "body": #{serialized_json}
+ })
+ end
+end
+```
+
+It looks similar to file layout but you must use string interpolation for method calls since it's not an ERB.
+
+Also note that we use percentage notation here to use double quotes. Using single quotes in inline string layout causes the error which might be resolved in other ways.
### Caching
Currently, Alba doesn't support caching, primarily due to the behavior of `ActiveRecord::Relation`'s cache. See [the issue](https://github.com/rails/rails/issues/41784).