{"id":13880216,"url":"https://github.com/zendesk/property_sets","last_synced_at":"2025-04-12T21:34:05.725Z","repository":{"id":1297879,"uuid":"1239928","full_name":"zendesk/property_sets","owner":"zendesk","description":"A way to store attributes in a side table.","archived":false,"fork":false,"pushed_at":"2025-01-13T12:58:23.000Z","size":387,"stargazers_count":51,"open_issues_count":3,"forks_count":8,"subscribers_count":417,"default_branch":"main","last_synced_at":"2025-04-04T01:09:52.287Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":"","language":"Ruby","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/zendesk.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":".github/CODEOWNERS","security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2011-01-10T23:28:58.000Z","updated_at":"2025-01-13T12:58:24.000Z","dependencies_parsed_at":"2023-11-06T11:48:29.344Z","dependency_job_id":"f23ac984-9a0c-4879-a429-2315a17df8cc","html_url":"https://github.com/zendesk/property_sets","commit_stats":{"total_commits":384,"total_committers":31,"mean_commits":"12.387096774193548","dds":0.6354166666666667,"last_synced_commit":"b00555625638bc22f75c92b9e752cc8a67c48cc5"},"previous_names":[],"tags_count":87,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/zendesk%2Fproperty_sets","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/zendesk%2Fproperty_sets/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/zendesk%2Fproperty_sets/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/zendesk%2Fproperty_sets/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/zendesk","download_url":"https://codeload.github.com/zendesk/property_sets/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":248636871,"owners_count":21137527,"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:52.398Z","updated_at":"2025-04-12T21:34:05.699Z","avatar_url":"https://github.com/zendesk.png","language":"Ruby","funding_links":[],"categories":["Ruby"],"sub_categories":[],"readme":"# Property sets [![Build Status](https://github.com/zendesk/property_sets/workflows/CI/badge.svg)](https://github.com/zendesk/property_sets/actions?query=workflow%3ACI)\n\nThis gem is a way for you to use a basic \"key/value\" store for storing attributes for a given model in a relational fashion where there's a row per attribute. Alternatively you'd need to add a new column per attribute to your main table, or serialize the attributes and their values using the [Active Record Store](https://api.rubyonrails.org/classes/ActiveRecord/Store.html).\n\n## Description\n\nYou configure the allowed stored properties by specifying these in the model:\n\n```ruby\nclass Account \u003c ActiveRecord::Base\n  property_set :settings do\n    property :version, :default =\u003e \"v1.0\"\n    property :featured, :protected =\u003e true\n    property :activated\n  end\n\n  property_set :texts do\n    property :epilogue\n  end\nend\n```\n\nThe declared properties can then be accessed runtime via the defined association:\n\n```ruby\n# Return the value of the version record for this account, or the default value if not set\naccount.settings.version\n\n# Update the version record with given value\naccount.settings.version = \"v1.1\"\n\n# Query the truth value of the property\naccount.settings.featured?\n\n# Short hand for setting one or more values\naccount.settings.set(:version =\u003e \"v1.2\", :activated =\u003e true)\n\n# Short hand for getting a hash with pairs for each key argument\naccount.settings.get([:version, :activated])\n```\n\nYou can also forward read, write and query methods to the properties with `PropertySets::Delegator`.\n\n```ruby\nclass Account \u003c ActiveRecord::Base\n  include PropertySets::Delegator\n  delegate_to_property_set :settings, :is_open =\u003e :open, :same =\u003e :same\nend\n\naccount.open #=\u003e account.settings.is_open\n```\n\nThese classes and their subclasses will inherit specified properties.\n\n### Validations\n\nProperty sets supports standard AR validations, although in a somewhat manual fashion.\n\n```ruby\nclass Account \u003c ActiveRecord::Base\n  property_set :settings do\n    property :version, :default =\u003e \"v1.0\"\n    property :featured, :protected =\u003e true\n\n    validates_format_of :value, :with =\u003e /v\\d+\\.\\d+/, :message =\u003e \"of version is invalid\",\n                        :if =\u003e Proc.new { |r| r.name.to_sym == :version }\n  end\nend\n```\n\nOn `account.save` this will result in an error record being added. You can also inspect the\nsetting record using `account.settings.version_record`\n\n### Bulk operations\n\nStored properties can also be updated with the update_attributes and update_attributes! methods by\nenabling nested attributes. Like this (from the test cases):\n\n```ruby\n@account.texts_attributes = [\n  { :name =\u003e \"foo\", :value =\u003e \"1\"  },\n  { :name =\u003e \"bar\", :value =\u003e \"0\"  }\n]\n```\n\nAnd for existing records:\n\n```ruby\n@account.update_attributes!(:texts_attributes =\u003e [\n  { :id =\u003e @account.texts.foo.id, :name =\u003e \"foo\", :value =\u003e \"0\"  },\n  { :id =\u003e @account.texts.bar.id, :name =\u003e \"bar\", :value =\u003e \"1\" }\n])\n```\n\nUsing nested attributes is subject to implementing your own security measures for mass update assignments.\nAlternatively, it is possible to use a custom hash structure:\n\n```ruby\nparams = {\n  :settings =\u003e { :version =\u003e \"v4.0\", :featured =\u003e \"1\" },\n  :texts    =\u003e { :epilogue =\u003e \"Wibble wobble\" }\n}\n\n@account.update_attributes(params)\n```\n\nThe above will not update `featured` as this has the protected flag set and is hence protected from\nmass updates.\n\n### View helpers\n\nWe support a couple of convenience mechanisms for building forms and putting the values into the above hash structure. So far, only support check boxes and radio buttons:\n\n```erb\n\u003c% form_for(:account, :html =\u003e { :method =\u003e :put }) do |f| %\u003e\n  \u003ch3\u003e\u003c%= f.property_set(:settings).check_box :activated %\u003e Activated?\u003c/h3\u003e\n  \u003ch3\u003e\u003c%= f.property_set(:settings).radio_button :hot, \"yes\" %\u003e Hot\u003c/h3\u003e\n  \u003ch3\u003e\u003c%= f.property_set(:settings).radio_button :not, \"no\" %\u003e Not\u003c/h3\u003e\n  \u003ch3\u003e\u003c%= f.property_set(:settings).select :level, [[\"One\", 1], [\"Two\", 2]] %\u003e\u003c/h3\u003e\n\u003c% end %\u003e\n```\n\n## Installation\n\nInstall the gem in your rails project by putting it in your Gemfile:\n\n```\ngem \"property_sets\"\n```\n\nAlso remember to create the storage table(s), if for example you are going to be using this with an accounts model and a \"settings\" property set, you can define the table like:\n\n```ruby\ncreate_table :account_settings do |t|\n  t.integer :account_id, :null =\u003e false\n  t.string  :name, :null =\u003e false\n  t.string  :value\n  t.timestamps\nend\n\nadd_index :account_settings, [ :account_id, :name ], :unique =\u003e true\n```\n\nIf you would like to serialize larger objects into your property sets, you can use a `TEXT` column type for value like this:\n\n```ruby\ncreate_table :account_settings do |t|\n  t.integer :account_id, :null =\u003e false\n  t.string  :name, :null =\u003e false\n  t.text    :value\n  t.timestamps\nend\n\nadd_index :account_settings, [ :account_id, :name ], :unique =\u003e true\n```\n\n### Storage table(s) on separate databases\n\nBy default, `property_sets` looks for the storage table(s) on the same database as the model. If you need the storage tables to live on a different database you can configure a custom connection class on a per-model basis:\n\n``` ruby\nclass MainConnectionClass \u003c ActiveRecord::Base\n  self.abstract_class = true\n\n  connects_to(database: { writing: foo })\nend\n\nclass SeparateDatabase \u003c ActiveRecord::Base\n  self.abstract_class = true\n\n  connects_to(database: { writing: bar })\nend\n\nclass Account \u003c MainConnectionClass\n  # Ensure you set this _before_ configuring the property sets.\n  self.property_sets_connection_class = SeparateDatabase\n\n  property_set :settings do\n    property :foo\n  end\nend\n```\n\nIn the above example, the `Accounts` table would live on the `foo` database and the storage table(s) will be written to the `bar` database.\n\n## Requirements\n\n* ActiveRecord\n* ActiveSupport\n\n## License and copyright\n\nCopyright 2013 Zendesk\n\nLicensed under the Apache License, Version 2.0 (the \"License\"); you may not use this file except in compliance with the License.\nYou may obtain a copy of the License at\n\nhttp://www.apache.org/licenses/LICENSE-2.0\n\nUnless required by applicable law or agreed to in writing, software distributed under the License is distributed on an \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fzendesk%2Fproperty_sets","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fzendesk%2Fproperty_sets","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fzendesk%2Fproperty_sets/lists"}