{"id":13879978,"url":"https://github.com/byroot/activerecord-typedstore","last_synced_at":"2025-05-15T08:10:36.525Z","repository":{"id":11436405,"uuid":"13891875","full_name":"byroot/activerecord-typedstore","owner":"byroot","description":"ActiveRecord::Store but with type definition","archived":false,"fork":false,"pushed_at":"2024-02-28T09:58:15.000Z","size":254,"stargazers_count":454,"open_issues_count":22,"forks_count":58,"subscribers_count":9,"default_branch":"master","last_synced_at":"2025-04-14T13:58:28.810Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"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/byroot.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE.txt","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null}},"created_at":"2013-10-26T22:04:54.000Z","updated_at":"2025-02-26T08:35:48.000Z","dependencies_parsed_at":"2024-01-03T02:24:28.744Z","dependency_job_id":"0c819e89-0d80-436e-b46b-4d237b9c9eac","html_url":"https://github.com/byroot/activerecord-typedstore","commit_stats":{"total_commits":224,"total_committers":26,"mean_commits":8.615384615384615,"dds":0.3214285714285714,"last_synced_commit":"0dae8a971e4c347a90085cf3fac9730d37165e50"},"previous_names":[],"tags_count":34,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/byroot%2Factiverecord-typedstore","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/byroot%2Factiverecord-typedstore/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/byroot%2Factiverecord-typedstore/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/byroot%2Factiverecord-typedstore/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/byroot","download_url":"https://codeload.github.com/byroot/activerecord-typedstore/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":254301433,"owners_count":22047904,"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":[],"created_at":"2024-08-06T08:02:41.752Z","updated_at":"2025-05-15T08:10:36.493Z","avatar_url":"https://github.com/byroot.png","language":"Ruby","funding_links":[],"categories":["Ruby","Gems"],"sub_categories":["Database Structure and Schema Management","Articles"],"readme":"# ActiveRecord::TypedStore\n\n[![Gem Version](https://badge.fury.io/rb/activerecord-typedstore.svg)](http://badge.fury.io/rb/activerecord-typedstore)\n\n[ActiveRecord::Store](http://api.rubyonrails.org/classes/ActiveRecord/Store.html) but with typed attributes.\n\n\n## Installation\n\nAdd this line to your application's Gemfile:\n\n    gem 'activerecord-typedstore'\n\nAnd then execute:\n\n    $ bundle\n\nOr install it yourself as:\n\n    $ gem install activerecord-typedstore\n\n## Usage\n\nIt works exactly like [ActiveRecord::Store documentation](http://api.rubyonrails.org/classes/ActiveRecord/Store.html) but you can declare the type of your attributes.\n\nAttributes definition is similar to activerecord's migrations:\n\n```ruby\n\nclass Shop \u003c ActiveRecord::Base\n\n  typed_store :settings do |s|\n    s.boolean :public, default: false, null: false\n    s.string :email\n    s.datetime :publish_at\n    s.integer :age, null: false\n\n    # You can define array attributes like in rails 4 and postgres\n    s.string :tags, array: true, default: [], null: false\n\n    # In addition to prevent null values you can prevent blank values\n    s.string :title, blank: false, default: 'Title'\n\n    # If you don't want to enforce a datatype but still like to have default handling\n    s.any :source, blank: false, default: 'web'\n  end\n\n  # You can use any ActiveModel validator\n  validates :age, presence: true\n\nend\n\n# Values are accessible like normal model attributes\nshop = Shop.new(email: 'george@cyclim.se')\nshop.public?        # =\u003e false\nshop.email          # =\u003e 'george@cyclim.se'\nshop.published_at   # =\u003e nil\n\n# Values are type casted\nshop.update_attributes(\n  age: '42',\n  published_at: '1984-06-08 13:57:12'\n)\nshop.age                # =\u003e 42\nshop.published_at.class #= DateTime\n\n# And changes are tracked\nshop.age_changed? # =\u003e false\nshop.age = 12\nshop.age_changed? # =\u003e true\nshop.age_was      # =\u003e 42\n\n# You can still use it as a regular store\nshop.settings[:unknown] = 'Hello World'\nshop.save\nshop.reload\nshop.settings[:unknown] # =\u003e 'Hello World'\n\n# You can group attributes with a prefix or suffix\ntyped_store(:browser, prefix: true) { |s| s.string :ip } # =\u003e #browser_ip\ntyped_store(:browser, prefix: :web) { |s| s.string :ip } # =\u003e #web_ip\ntyped_store(:browser, suffix: true) { |s| s.string :ip } # =\u003e #ip_browser\ntyped_store(:browser, suffix: :web) { |s| s.string :ip } # =\u003e #ip_web\n\n# If you only want type casting and default handling without accessors\n\n# you can disable them store wide\ntyped_store :settings, accessors: false do |s|\n  # ...\nend\n\n# or on a per attribute basis\ntyped_store :settings do |s|\n  s.integer :age\n  s.string :postal_code, accessor: false\nend\n\n```\n\nType casting rules and attribute behavior are exactly the same as for real database columns.\nActually the only difference is that you won't be able to query on these attributes (unless you use JSON or Postgres HStore types) and that you don't need to do a migration to add / remove an attribute.\n\nIf not, then please fill in an issue.\n\n## Serialization methods\n\nJust like for store, you can use any custom coder:\n\n```ruby\nmodule Base64MarshalCoder\n  extend self\n\n  def load(data)\n    return {} unless data\n    Marshal.load(Base64.decode64(data))\n  end\n\n  def dump(data)\n    Base64.encode64(Marshal.dump(data || {}))\n  end\n\nend\n\ntyped_store :settings, coder: Base64MarshalCoder do |s|\n  # ...\nend\n```\n\nIf you want to use JSON column or Postgres HStore types, then you can pass in `ActiveRecord::TypedStore::IdentityCoder` as the coder.\n\n## HStore limitations\n\nIf you want to persist your store in a Postgres HStore, then there is some limitations imposed by the current HStore implementation in Postgres.\nSince HStore can only store strings:\n\n  - `array` attributes won't work\n  - `any` attributes will be converted to string\n\nIf you use HStore because you need to be able to query the store from SQL, and any of these limitations are an issue for you,\nthen you could probably use the JSON column type, which do not suffer from these limitations and is also queriable. \n\n## Contributing\n\n1. Fork it\n2. Create your feature branch (`git checkout -b my-new-feature`)\n3. Commit your changes (`git commit -am 'Add some feature'`)\n4. Push to the branch (`git push origin my-new-feature`)\n5. Create new Pull Request\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fbyroot%2Factiverecord-typedstore","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fbyroot%2Factiverecord-typedstore","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fbyroot%2Factiverecord-typedstore/lists"}