property_sets 1.0.4 → 1.0.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
data/README.md CHANGED
@@ -6,112 +6,131 @@ This gem is a way for you to use a basic "key/value" store for storing attribute
6
6
 
7
7
  You configure the allowed stored properties by specifying these in the model:
8
8
 
9
- class Account < ActiveRecord::Base
10
- property_set :settings do
11
- property :version, :default => "v1.0"
12
- property :featured, :protected => true
13
- property :activated
14
- end
15
-
16
- property_set :texts do
17
- property :epilogue
18
- end
19
- end
9
+ ```ruby
10
+ class Account < ActiveRecord::Base
11
+ property_set :settings do
12
+ property :version, :default => "v1.0"
13
+ property :featured, :protected => true
14
+ property :activated
15
+ end
16
+
17
+ property_set :texts do
18
+ property :epilogue
19
+ end
20
+ end
21
+ ```
20
22
 
21
23
  The declared properties can then be accessed runtime via the defined association:
22
24
 
23
- # Return the value of the version record for this account, or the default value if not set
24
- account.settings.version
25
+ ```ruby
26
+ # Return the value of the version record for this account, or the default value if not set
27
+ account.settings.version
25
28
 
26
- # Update the version record with given value
27
- account.settings.version = "v1.1"
29
+ # Update the version record with given value
30
+ account.settings.version = "v1.1"
28
31
 
29
- # Query the truth value of the property
30
- account.settings.featured?
32
+ # Query the truth value of the property
33
+ account.settings.featured?
31
34
 
32
- # Short hand for setting one or more values
33
- account.settings.set(:version => "v1.2", :activated => true)
35
+ # Short hand for setting one or more values
36
+ account.settings.set(:version => "v1.2", :activated => true)
37
+ ```
34
38
 
35
39
  ### Validations
36
40
 
37
41
  Property sets supports standard AR validations, although in a somewhat manual fashion.
38
42
 
39
- class Account < ActiveRecord::Base
40
- property_set :settings do
41
- property :version, :default => "v1.0"
42
- property :featured, :protected => true
43
+ ```ruby
44
+ class Account < ActiveRecord::Base
45
+ property_set :settings do
46
+ property :version, :default => "v1.0"
47
+ property :featured, :protected => true
43
48
 
44
- validates_format_of :value, :with => /v\d+\.\d+/, :message => "of version is invalid",
45
- :if => Proc.new { |r| r.name.to_sym == :version }
46
- end
47
- end
49
+ validates_format_of :value, :with => /v\d+\.\d+/, :message => "of version is invalid",
50
+ :if => Proc.new { |r| r.name.to_sym == :version }
51
+ end
52
+ end
53
+ ```
48
54
 
49
- On +account.save+ this will result in an error record being added. You can also inspect the
50
- setting record using +account.settings.version_record+
55
+ On `account.save` this will result in an error record being added. You can also inspect the
56
+ setting record using `account.settings.version_record`
51
57
 
52
58
  ### Bulk operations
53
59
 
54
60
  Stored properties can also be updated with the update_attributes and update_attributes! methods by
55
61
  enabling nested attributes. Like this (from the test cases):
56
62
 
57
- @account.texts_attributes = [
58
- { :name => "foo", :value => "1" },
59
- { :name => "bar", :value => "0" }
60
- ]
63
+ ```ruby
64
+ @account.texts_attributes = [
65
+ { :name => "foo", :value => "1" },
66
+ { :name => "bar", :value => "0" }
67
+ ]
68
+ ```
61
69
 
62
70
  And for existing records:
63
71
 
64
- @account.update_attributes!(:texts_attributes => [
65
- { :id => @account.texts.foo.id, :name => "foo", :value => "0" },
66
- { :id => @account.texts.bar.id, :name => "bar", :value => "1" }
67
- ])
72
+ ```ruby
73
+ @account.update_attributes!(:texts_attributes => [
74
+ { :id => @account.texts.foo.id, :name => "foo", :value => "0" },
75
+ { :id => @account.texts.bar.id, :name => "bar", :value => "1" }
76
+ ])
77
+ ```
68
78
 
69
79
  Using nested attributes is subject to implementing your own security measures for mass update assignments.
70
80
  Alternatively, it is possible to use a custom hash structure:
71
81
 
72
- params = {
73
- :settings => { :version => "v4.0", :featured => "1" },
74
- :texts => { :epilogue => "Wibble wobble" }
75
- }
76
- @account.update_attributes(params)
82
+ ```ruby
83
+ params = {
84
+ :settings => { :version => "v4.0", :featured => "1" },
85
+ :texts => { :epilogue => "Wibble wobble" }
86
+ }
77
87
 
78
- The above will not update +featured+ as this has the protected flag set and is hence protected from
88
+ @account.update_attributes(params)
89
+ ```
90
+
91
+ The above will not update `featured` as this has the protected flag set and is hence protected from
79
92
  mass updates.
80
93
 
81
94
  ### View helpers
82
95
 
83
96
  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:
84
97
 
85
- <% form_for(:account, :html => { :method => :put }) do |f| %>
86
- <h3><%= f.property_set(:settings).check_box :activated %> Activated?</h3>
87
- <h3><%= f.property_set(:settings).radio_button :hot, "yes" %> Hot</h3>
88
- <h3><%= f.property_set(:settings).radio_button :not, "no" %> Not</h3>
89
- <h3><%= f.property_set(:settings).select :level, [["One", 1], ["Two", 2]] %></h3>
90
- <% end %>
98
+ ```erb
99
+ <% form_for(:account, :html => { :method => :put }) do |f| %>
100
+ <h3><%= f.property_set(:settings).check_box :activated %> Activated?</h3>
101
+ <h3><%= f.property_set(:settings).radio_button :hot, "yes" %> Hot</h3>
102
+ <h3><%= f.property_set(:settings).radio_button :not, "no" %> Not</h3>
103
+ <h3><%= f.property_set(:settings).select :level, [["One", 1], ["Two", 2]] %></h3>
104
+ <% end %>
105
+ ```
91
106
 
92
107
  ## Installation
93
108
 
94
109
  Install the gem in your rails project by putting it in your Gemfile:
95
110
 
96
- gem "property_sets"
111
+ ```
112
+ gem "property_sets"
113
+ ```
97
114
 
98
115
  Also 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:
99
116
 
100
- create_table :account_settings do |t|
101
- t.integer :account_id, :null => false
102
- t.string :name, :null => false
103
- t.string :value
104
- t.timestamps
105
- end
117
+ ```ruby
118
+ create_table :account_settings do |t|
119
+ t.integer :account_id, :null => false
120
+ t.string :name, :null => false
121
+ t.string :value
122
+ t.timestamps
123
+ end
106
124
 
107
- add_index :account_settings, [ :account_id, :name ], :unique => true
125
+ add_index :account_settings, [ :account_id, :name ], :unique => true
126
+ ```
108
127
 
109
128
  ## Requirements
110
129
 
111
130
  * ActiveRecord
112
131
  * ActiveSupport
113
132
 
114
- ## License
133
+ ## License and copyright
115
134
 
116
135
  Copyright 2013 Zendesk
117
136
 
@@ -4,14 +4,13 @@ module ActionView
4
4
  module Helpers
5
5
  class FormBuilder
6
6
  class PropertySetFormBuilderProxy
7
- attr_accessor :property_set
8
- attr_accessor :template
9
- attr_accessor :object_name
10
-
11
- def initialize(property_set, template, object_name)
12
- self.property_set = property_set
13
- self.template = template
14
- self.object_name = object_name
7
+ attr_reader :property_set, :template, :object_name, :object
8
+
9
+ def initialize(property_set, template, object_name, object)
10
+ @property_set = property_set
11
+ @template = template
12
+ @object_name = object_name
13
+ @object = object
15
14
  end
16
15
 
17
16
  def check_box(property, options = {}, checked_value = "1", unchecked_value = "0")
@@ -46,29 +45,33 @@ module ActionView
46
45
  template.select("#{object_name}[#{property_set}]", property, choices, { :selected => current_value }, html_options )
47
46
  end
48
47
 
48
+ private
49
+
49
50
  def prepare_id_name(property, options)
50
51
  throw "Invalid options type #{options.inspect}" unless options.is_a?(Hash)
51
52
 
52
53
  options.clone.tap do |prepared_options|
53
- instance = template.instance_variable_get("@#{object_name}")
54
-
55
- throw "No @#{object_name} in scope" if instance.nil?
56
- throw "The property_set_check_box only works on models with property set #{property_set}" unless instance.respond_to?(property_set)
57
-
54
+ prepared_options[:object] = object || fetch_target_object
58
55
  prepared_options[:id] ||= "#{object_name}_#{property_set}_#{property}"
59
56
  prepared_options[:name] = "#{object_name}[#{property_set}][#{property}]"
60
- prepared_options[:object] = instance
61
57
  end
62
58
  end
63
59
 
60
+ def fetch_target_object
61
+ instance = template.instance_variable_get("@#{object_name}")
62
+
63
+ throw "No @#{object_name} in scope" if instance.nil?
64
+ throw "The property_set_check_box only works on models with property set #{property_set}" unless instance.respond_to?(property_set)
65
+
66
+ instance
67
+ end
68
+
64
69
  def prepare_options(property, options, &block)
65
70
  options = prepare_id_name(property, options)
66
71
  options[:checked] = yield(options[:object].send(property_set))
67
72
  options
68
73
  end
69
74
 
70
- private
71
-
72
75
  def cast_boolean(value)
73
76
  case value
74
77
  when TrueClass then '1'
@@ -80,7 +83,7 @@ module ActionView
80
83
  end
81
84
 
82
85
  def property_set(identifier)
83
- PropertySetFormBuilderProxy.new(identifier, @template, @object_name)
86
+ PropertySetFormBuilderProxy.new(identifier, @template, object_name, object)
84
87
  end
85
88
 
86
89
  end
@@ -1,4 +1,4 @@
1
- Gem::Specification.new "property_sets", "1.0.4" do |s|
1
+ Gem::Specification.new "property_sets", "1.0.5" do |s|
2
2
  s.summary = "Property sets for ActiveRecord."
3
3
  s.description = "This gem is an ActiveRecord extension which provides a convenient interface for managing per row properties."
4
4
  s.authors = ["Morten Primdahl"]
@@ -11,8 +11,6 @@ class TestViewExtensions < ActiveSupport::TestCase
11
11
  @template = stub
12
12
  @builder = ActionView::Helpers::FormBuilder.new(@object_name, @object, @template, {}, 'proc')
13
13
  @proxy = @builder.property_set(@property_set)
14
-
15
- @template.stubs(:instance_variable_get).with("@#{@object_name}").returns(@object)
16
14
  end
17
15
 
18
16
  should "provide a form builder proxy" do
@@ -20,6 +18,17 @@ class TestViewExtensions < ActiveSupport::TestCase
20
18
  assert_equal @property_set, @proxy.property_set
21
19
  end
22
20
 
21
+ should "fetch the target object when not available" do
22
+ @builder = ActionView::Helpers::FormBuilder.new(@object_name, nil, @template, {}, 'proc')
23
+ @proxy = @builder.property_set(@property_set)
24
+
25
+ @object.stubs(@property_set).returns(stub(@property => 'value'))
26
+ @template.stubs(:hidden_field)
27
+
28
+ @template.expects(:instance_variable_get).with("@#{@object_name}").returns(@object)
29
+ @proxy.hidden_field(@property)
30
+ end
31
+
23
32
  context "#check_box" do
24
33
  context "when called with checked true for a truth value" do
25
34
  setup do
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: property_sets
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.0.4
4
+ version: 1.0.5
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2013-04-09 00:00:00.000000000 Z
12
+ date: 2013-04-19 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: activesupport