# Property sets [![Build Status](https://secure.travis-ci.org/zendesk/property_sets.png)](http://travis-ci.org/zendesk/property_sets) This 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 [ActiveRecord 3.2 store](https://github.com/rails/rails/commit/85b64f98d100d37b3a232c315daa10fad37dccdc). ## Description You configure the allowed stored properties by specifying these in the model: ```ruby class Account < ActiveRecord::Base property_set :settings do property :version, :default => "v1.0" property :featured, :protected => true property :activated end property_set :texts do property :epilogue end end ``` The declared properties can then be accessed runtime via the defined association: ```ruby # Return the value of the version record for this account, or the default value if not set account.settings.version # Update the version record with given value account.settings.version = "v1.1" # Query the truth value of the property account.settings.featured? # Short hand for setting one or more values account.settings.set(:version => "v1.2", :activated => true) # Short hand for getting a hash with pairs for each key argument account.settings.get([:version, :activated]) ``` ### Validations Property sets supports standard AR validations, although in a somewhat manual fashion. ```ruby class Account < ActiveRecord::Base property_set :settings do property :version, :default => "v1.0" property :featured, :protected => true validates_format_of :value, :with => /v\d+\.\d+/, :message => "of version is invalid", :if => Proc.new { |r| r.name.to_sym == :version } end end ``` On `account.save` this will result in an error record being added. You can also inspect the setting record using `account.settings.version_record` ### Bulk operations Stored properties can also be updated with the update_attributes and update_attributes! methods by enabling nested attributes. Like this (from the test cases): ```ruby @account.texts_attributes = [ { :name => "foo", :value => "1" }, { :name => "bar", :value => "0" } ] ``` And for existing records: ```ruby @account.update_attributes!(:texts_attributes => [ { :id => @account.texts.foo.id, :name => "foo", :value => "0" }, { :id => @account.texts.bar.id, :name => "bar", :value => "1" } ]) ``` Using nested attributes is subject to implementing your own security measures for mass update assignments. Alternatively, it is possible to use a custom hash structure: ```ruby params = { :settings => { :version => "v4.0", :featured => "1" }, :texts => { :epilogue => "Wibble wobble" } } @account.update_attributes(params) ``` The above will not update `featured` as this has the protected flag set and is hence protected from mass updates. ### View helpers We 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: ```erb <% form_for(:account, :html => { :method => :put }) do |f| %>