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).