{"id":13878064,"url":"https://github.com/MoskitoHero/barley","last_synced_at":"2025-07-16T14:30:52.574Z","repository":{"id":199203609,"uuid":"702317928","full_name":"MoskitoHero/barley","owner":"MoskitoHero","description":"Barley is a fast and efficient ActiveModel serializer","archived":false,"fork":false,"pushed_at":"2024-09-25T03:43:52.000Z","size":1096,"stargazers_count":80,"open_issues_count":1,"forks_count":3,"subscribers_count":1,"default_branch":"main","last_synced_at":"2024-11-19T15:47:51.593Z","etag":null,"topics":["activerecord","cache","rails","ruby","serializer","type-check"],"latest_commit_sha":null,"homepage":"","language":"Ruby","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/MoskitoHero.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":"CONTRIBUTING.md","funding":null,"license":"MIT-LICENSE","code_of_conduct":"CODE_OF_CONDUCT.md","threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":"SECURITY.md","support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2023-10-09T04:53:49.000Z","updated_at":"2024-09-25T03:40:12.000Z","dependencies_parsed_at":"2023-10-16T10:49:59.393Z","dependency_job_id":"23b016e3-35eb-430a-986b-aeda42d4151d","html_url":"https://github.com/MoskitoHero/barley","commit_stats":null,"previous_names":["moskitohero/barley"],"tags_count":10,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/MoskitoHero%2Fbarley","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/MoskitoHero%2Fbarley/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/MoskitoHero%2Fbarley/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/MoskitoHero%2Fbarley/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/MoskitoHero","download_url":"https://codeload.github.com/MoskitoHero/barley/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":226134226,"owners_count":17578778,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["activerecord","cache","rails","ruby","serializer","type-check"],"created_at":"2024-08-06T08:01:38.836Z","updated_at":"2025-07-16T14:30:52.562Z","avatar_url":"https://github.com/MoskitoHero.png","language":"Ruby","funding_links":[],"categories":["Ruby"],"sub_categories":[],"readme":"![Barley loqo](https://i.imgur.com/cJJRA0i.png)\n\n![Test suite badge](https://github.com/MoskitoHero/barley/actions/workflows/ruby.yml/badge.svg)\n[![Gem Version](https://badge.fury.io/rb/barley.svg)](https://badge.fury.io/rb/barley)\n![Static Badge](https://img.shields.io/badge/Cereal%20-%20100%25%20-%20darklime)\n\nBarley is a fast and efficient ActiveModel serializer.\n\nCerealize your ActiveModel objects into flat hashes with a clear, yet versatile DSL, and caching and type-checking baked in. Our daily bread is to make your API faster.\n\nYou don't believe us? Check out the [benchmarks](https://github.com/MoskitoHero/barley/tree/main/benchmarks#readme). 😎\n\n## API documentation\n[Check out the API documentation here](https://rubydoc.info/github/MoskitoHero/barley/main).\n\n## Usage\nAdd the `Barley::Serializable` module to your ActiveModel object.\n\n```ruby\n# /app/models/user.rb\nclass User \u003c ApplicationRecord\n  include Barley::Serializable\nend\n```\n\nThen define your attributes and associations in a serializer class.\n\n```ruby\n# /app/serializers/user_serializer.rb\nclass UserSerializer \u003c Barley::Serializer\n\n  attributes id: Types::Strict::Integer, :name\n\n  attribute :email\n  attribute :value, type: Types::Coercible::Integer\n\n  many :posts\n\n  many :posts, key_name: :featured, scope: :featured\n\n  many :posts, key_name: :popular, scope: -\u003e { where(\"views \u003e 10_000\").limit(3) }\n\n  many :posts, key_name: :in_current_language, scope: -\u003e (context) { where(language: context.language) }\n\n  one :group, serializer: CustomGroupSerializer\n\n  many :related_users, key: :friends, cache: true\n\n  one :profile, cache: { expires_in: 1.day } do\n    attributes :avatar, :social_url\n\n    attribute :badges do\n      object.badges.map(\u0026:display_name)\n    end\n  end\n\nend\n```\n\nThen just use the `as_json` method on your model.\n\n```ruby\nuser = User.find(1)\nuser.as_json(only: [:id, :name, posts: [:id, :title]])\n```\n\n## Installation\nAdd this line to your application's Gemfile:\n\n```ruby\ngem \"barley\"\n```\n\nAnd then execute:\n```bash\n$ bundle\n```\n\nOr install it yourself as:\n```bash\n$ gem install barley\n```\n\n## Defining the serializer\n\nBarley uses the model name to find the serializer class. For example, if you have a `User` model, Barley will look for a `UserSerializer` class.\n\nYou can also define the serializer class with the `serializer` macro.\n\n```ruby\n# /app/models/user.rb\nclass User \u003c ApplicationRecord\n  include Barley::Serializable\n\n  serializer UserSerializer\nend\n```\n\n## DSL\n\n### Attributes\nYou can define attributes with the `attributes` macro.\n\n```ruby\n  attributes :id, :name, :email, :created_at, :updated_at\n```\n\nYou can also define attributes one by one, or a mix of both.\n\n```ruby\n  attributes :id, :name, :email\n  attribute :created_at\n  attribute :updated_at\n```\n\nYou can also define a custom attribute with a block. You will have a `object` variable available in the block. It is the object you are serializing.\n\n```ruby\n  attribute :full_name do\n    \"#{object.first_name} #{object.last_name}\"\n  end\n```\n\nYou can also set a custom key name for the attribute with the `key_name` option.\n\n```ruby\n  attribute :updated_at, key: :last_change\n```\n\n### Associations\n\n#### One-to-one\nYou can define a one-to-one association with the `one` macro.\n\n```ruby\n  one :group\n```\n\n##### Custom serializer and caching\nYou can define a custom serializer for the association with the `serializer` option, and / or caching options with the `cache` option.\n\n```ruby\n  one :group, serializer: CustomGroupSerializer, cache: { expires_in: 1.hour }\n```\n\nYou can of course define serializers with inner classes for simple needs.\n\n```ruby\nclass UserSerializer \u003c Barley::Serializer\n  attributes :id, :name, :email, :created_at, :updated_at\n\n  one :group, serializer: LocalGroupSerializer\n\n    class LocalGroupSerializer \u003c Barley::Serializer\n        attributes :id, :name\n    end\nend\n```\n\n##### Key name\n\nYou can also pass a key name for the association with the `key_name` option.\n\n```ruby\n  one :group, key_name: :team\n```\n\n#### One-to-many\nYou can define a one-to-many association with the `many` macro.\n\n```ruby\n  many :posts\n```\n\n##### Custom serializer and caching\n\nYou can define a custom serializer for the association with the `serializer` option, and / or caching options with the `cache` option.\n\n```ruby\n  many :posts, serializer: CustomPostSerializer, cache: { expires_in: 1.hour }\n```\n\n##### Scope\nYou can pass a scope to the association with the `scope` option. It can either be a symbol referencing a named scope on your associated model, or a lambda.\n\n```ruby\n  many :posts, scope: :published # given you have a scope named `published` on your Post model\n```\n\n```ruby\n  many :posts, scope: -\u003e { where(published: true).limit(4) }\n```\n\nYou can also pass a context to the lambda. See the [context section](#context) for more details.\n\n```ruby\n  many :posts, scope: -\u003e (context) { where(language: context.language) }\n```\n\n##### Key name\nYou can also pass a key name for the association with the `key_name` option.\n\n```ruby\n  many :posts, key_name: :articles\n```\n\n### Associations with blocks\nFeel like using a block to define your associations? You can do that too.\n\n```ruby\n  one :group do\n    attributes :id, :name\n  end\n```\n\n```ruby\n  many :posts do\n    attributes :id, :title, :body\n\n    one :author do\n      attributes :name, :email\n    end\n  end\n```\n\nOf course, all the options available for the `one` and `many` macros are also available for the block syntax.\n\n```ruby\n  many :posts, key_name: :featured do\n    attributes :id, :title, :body\n  end\n```\n\n## Context\n\nYou can pass a context to the serializer with the `with_context` method.\n\n```ruby\nserializer = PostSerializer.new(Post.last).with_context(current_user: current_user)\n```\n\nThis context will be available in the serializer with the `context` method. It is also available in nested serializers.\n\n```ruby\nclass PostSerializer \u003c Barley::Serializer\n  attributes :id, :title, :body\n\n  attribute :is_owner do\n    object.user == context.current_user\n  end\n\n  many :comments do\n    many :likes do\n      attribute :is_owner do\n        object.user == context.current_user # context is here too!\n      end\n    end\n  end\nend\n```\n\nThe context is also available in the scope of the lambda passed to the `scope` option of the `many` macro. See the [scope section](#scope) for more details.\n\n```ruby\n  many :posts, scope: -\u003e (context) { where(language: context.language) }\n```\n\n### Using a custom context object\nBarley generates a Struct from the context hash you pass to the with_context method. But you can also pass a custom context object directly in the initializer instead.\n\n```ruby\nmy_context = Struct.new(:current_user).new(current_user)\n\nserializer = PostSerializer.new(Post.last, context: my_context)\n```\n\n## Generators\nYou have two generators available. One to generate the serializer class:\n\n```shell\nrails generate barley:serializer User\n# or\nrails generate barley:serializer User --name=CustomUserSerializer\n```\n\nAnd one to generate both the serializer class and add the module to the model:\n\n```shell\nrails generate barley:serializable User\n# or\nrails generate barley:serializable User --name=CustomUserSerializer\n```\n\n## Serialization options\nYou can pass a hash of options to the `as_json` method.\n\n```ruby\nuser = User.find(1)\nuser.as_json(serializer: CustomUserSerializer, cache: { expires_in: 1.hour })\n```\n\nBeware, this gem overrides the `as_json` method on your model. Calling `as_json` with `include`, `only`, or `except` options will not work as expected.\n\nWhy? We believe it defeats the purpose of this gem. If you want to customize the serialization of your model, you should use a serializer class.\n\n\n## Caching\nBarley supports caching out of the box. Just pass `cache: true` to the `serializer` macro.\n\n```ruby\n# /app/models/user.rb\n# ...\nserializer UserSerializer, cache: true\n```\n\nOr you can pass a hash of options to the `serializer` macro.\n\n```ruby\n# /app/models/user.rb\n# ...\nserializer UserSerializer, cache: { expires_in: 1.hour }\n```\n\n### Caching options\nBarley uses the MemoryStore by default. You can change the cache store with the `cache_store` option in an initializer.\n\n```ruby\n# /config/initializers/barley.rb\nBarley.configure do |config|\n  config.cache_store = ActiveSupport::Cache::RedisCacheStore.new\nend\n```\n\n## Type checking\nBarley can check the type of the object you are serializing with the [dry-types](https://dry-rb.org/gems/dry-types/main/) gem.\n\nIt will raise an error if the object is not of the expected type, or coerce it to the correct type and perform constraints checks.\n\n```ruby\nmodule Types\n  include Dry.Types()\nend\n\nclass UserSerializer \u003c Barley::Serializer\n  attributes id: Types::Strict::Integer, name: Types::Strict::String, email: Types::Strict::String.constrained(format: URI::MailTo::EMAIL_REGEXP)\n\n  attribute :role, type: Types::Coercible::String do\n    object.role.integer_or_string_coercible_value\n  end\nend\n```\n\nCheck out [dry-types](https://dry-rb.org/gems/dry-types/main/) for all options and available types.\n\n## Breakfast mode 🤡 (coming soon)\nYou will soon be able to replace all occurrences of `Serializer` with `Cerealizer` in your codebase. Just for fun. And for free.\n\n```ruby\n# /app/models/user.rb\nclass User \u003c ApplicationRecord\n  include Barley::Cerealizable\n\n  cerealizer UserCerealizer\nend\n\n# app/cerealizers/user_cerealizer.rb\nclass UserCerealizer \u003c Barley::Cerealizer\n  attributes :id, :name, :email, :created_at, :updated_at\n\n  many :posts\n  one :group\nend\n```\n\n```shell\nrails generate barley:cerealizer User\n# etc.\n```\n\nAh ah ah. This is so funny.\n\n*Note: we are thinking about adding a `Surrealizer` class for the most advanced users. Stay tuned.*\n\n## JSON:API\nBarley does not serialize to the JSON:API standard. We prefer to keep it simple and fast.\n\n## License\nThe gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).\n\nThe logo is made from an asset from [onlinewebfonts.com](https://www.onlinewebfonts.com/icon), licensed by CC BY 4.0.\n\n## Contributing\nYou can contribute in several ways: reporting bugs, suggesting features, or contributing code. See [our contributing guidelines](CONTRIBUTING.md)\n\nMake sure you adhere to [our code of conduct](CODE_OF_CONDUCT.md). We aim to keep this project open and inclusive.\n\n## Security\n\nPlease refer to our [security guidelines](SECURITY.md)\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2FMoskitoHero%2Fbarley","html_url":"https://awesome.ecosyste.ms/projects/github.com%2FMoskitoHero%2Fbarley","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2FMoskitoHero%2Fbarley/lists"}