freeform 0.0.3.rc1 → 0.0.3.rc2
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 +22 -9
- data/lib/freeform/form/nested.rb +32 -9
- data/lib/freeform/form/property.rb +3 -0
- data/lib/freeform/version.rb +1 -1
- data/spec/acceptance_spec.rb +4 -7
- data/spec/form/nested_spec.rb +14 -8
- data/spec/form/validation_spec.rb +14 -10
- metadata +1 -1
data/README.md
CHANGED
@@ -12,7 +12,7 @@ FreeForm is designed primarily with Rails in mind, but it should work on any Rub
|
|
12
12
|
|
13
13
|
Add this line to your application's Gemfile:
|
14
14
|
|
15
|
-
gem 'freeform'
|
15
|
+
gem 'freeform', '~> 0.0.3rc2'
|
16
16
|
|
17
17
|
And then execute:
|
18
18
|
|
@@ -212,16 +212,28 @@ form.build_phone_numbers(:phone => Phone.new)
|
|
212
212
|
form.build_phone_number(:phone => Phone.new)
|
213
213
|
```
|
214
214
|
|
215
|
-
|
215
|
+
**Working with nested_form gem**
|
216
|
+
In order to support the `nested_form` gem, FreeForm currently uses a bit of hackiness. You actually need to specify an option on your nested forms called `class_initializer`, that points to a class method to use to specify the default parameters. You can either provide the method hardcoded into the class, or set it externally. It accepts either a hardcoded hash, or a Proc.
|
216
217
|
```ruby
|
217
|
-
|
218
|
-
:user
|
219
|
-
:phone_numbers_form_initializer => {:phone => Phone.new} )
|
218
|
+
class UserForm < FreeForm::Form
|
219
|
+
form_models :user
|
220
220
|
|
221
|
-
|
222
|
-
|
221
|
+
property :username, :on => :user
|
222
|
+
property :email, :on => :user
|
223
|
+
|
224
|
+
nested_form :phone_numbers, :class_initializer => :phone_initializer do
|
225
|
+
form_models :phone
|
226
|
+
|
227
|
+
property :area_code, :on => :phone
|
228
|
+
property :number, :on => :phone
|
229
|
+
end
|
230
|
+
end
|
231
|
+
|
232
|
+
UserForm.phone_initializer = lambda { { :phone => Phone.new } }
|
233
|
+
form = UserForm.new( :user => User.new )
|
234
|
+
form.build_phone_number # Uses Phone.new to initialize the nested form.
|
223
235
|
```
|
224
|
-
|
236
|
+
I apologize for the ugliness - In the future, I plan to roll FreeForm's own version of the `nested_form` javascript functionality.
|
225
237
|
|
226
238
|
## Initialize With Care!
|
227
239
|
|
@@ -238,7 +250,7 @@ class UserForm < FreeForm::Form
|
|
238
250
|
property :username, :on => :user
|
239
251
|
property :email, :on => :user
|
240
252
|
|
241
|
-
nested_form :phone_numbers do
|
253
|
+
nested_form :phone_numbers, :class_initializer => :phone_initializer do
|
242
254
|
form_models :phone
|
243
255
|
|
244
256
|
property :area_code, :on => :phone
|
@@ -253,6 +265,7 @@ Will the current_user's phone numbers automatically appear as nested forms? **No
|
|
253
265
|
If you want them there, put them there, like this:
|
254
266
|
|
255
267
|
```ruby
|
268
|
+
UserForm.phone_initializer = lambda { { :phone => current_user.phone_numbers.build } }
|
256
269
|
current_user.phone_numbers.each do |phone_number|
|
257
270
|
form.build_phone_number(:phone => phone_number)
|
258
271
|
end
|
data/lib/freeform/form/nested.rb
CHANGED
@@ -12,6 +12,21 @@ module FreeForm
|
|
12
12
|
attr_accessor :nested_forms
|
13
13
|
|
14
14
|
def nested_form(attribute, options={}, &block)
|
15
|
+
# Specify the class method on which we're defining the initializer for this form.
|
16
|
+
parent_class = self
|
17
|
+
initializer_method = options[:class_initializer]
|
18
|
+
unless initializer_method.nil?
|
19
|
+
define_singleton_method(:"#{initializer_method}") do
|
20
|
+
var = instance_variable_get(:"@#{initializer_method}")
|
21
|
+
var ||= {}
|
22
|
+
var
|
23
|
+
end
|
24
|
+
|
25
|
+
define_singleton_method(:"#{initializer_method}=") do |val|
|
26
|
+
instance_variable_set(:"@#{initializer_method}", val)
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
15
30
|
# Define an attr_accessor for the parent class to hold this attribute
|
16
31
|
declared_model(attribute)
|
17
32
|
|
@@ -19,6 +34,22 @@ module FreeForm
|
|
19
34
|
nested_form_class = Class.new(FreeForm::Form) do
|
20
35
|
include FreeForm::Property
|
21
36
|
self.instance_eval(&block)
|
37
|
+
|
38
|
+
define_singleton_method(:default_initializer) do
|
39
|
+
unless initializer_method.nil?
|
40
|
+
method = parent_class.send(initializer_method)
|
41
|
+
if method.is_a? Proc
|
42
|
+
method.call
|
43
|
+
else
|
44
|
+
method
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
def initialize(p={}, *args)
|
50
|
+
p = self.class.default_initializer.merge(p)
|
51
|
+
super(p, *args)
|
52
|
+
end
|
22
53
|
end
|
23
54
|
self.const_set("#{attribute.to_s.camelize}Form", nested_form_class)
|
24
55
|
|
@@ -53,18 +84,10 @@ module FreeForm
|
|
53
84
|
@nested_attributes ||= []
|
54
85
|
end
|
55
86
|
|
56
|
-
# Example: form.address_form_initializer (aliased to form.addresses_form_initializer)
|
57
|
-
attr_accessor :"#{attribute}_form_initializer"
|
58
|
-
alias_method :"#{singularized_attribute}_form_initializer", :"#{attribute}_form_initializer"
|
59
|
-
alias_method :"#{singularized_attribute}_form_initializer=", :"#{attribute}_form_initializer="
|
60
|
-
|
61
87
|
# Example: form.build_addresses (optional custom initializer)
|
62
|
-
define_method(:"build_#{attribute}") do |initializer=
|
88
|
+
define_method(:"build_#{attribute}") do |initializer={}|
|
63
89
|
# Get correct class
|
64
90
|
form_class = self.class.nested_forms[:"#{attribute}"]
|
65
|
-
|
66
|
-
# Set default intializer if none provided
|
67
|
-
initializer ||= send("#{attribute}_form_initializer").call
|
68
91
|
|
69
92
|
# Build new model
|
70
93
|
form_model = form_class.new(initializer)
|
data/lib/freeform/version.rb
CHANGED
data/spec/acceptance_spec.rb
CHANGED
@@ -57,12 +57,12 @@ describe FreeForm::Form do
|
|
57
57
|
allow_destroy_on_save
|
58
58
|
|
59
59
|
property :username, :on => :user
|
60
|
-
property :email, :on => :user
|
60
|
+
property :email, :on => :user
|
61
61
|
property :street, :on => :address
|
62
62
|
property :city, :on => :address
|
63
63
|
property :state, :on => :address
|
64
64
|
|
65
|
-
has_many :phone_numbers do
|
65
|
+
has_many :phone_numbers, :class_initializer => :phone_number_initializer do
|
66
66
|
form_model :phone
|
67
67
|
validate_models
|
68
68
|
allow_destroy_on_save
|
@@ -79,11 +79,8 @@ describe FreeForm::Form do
|
|
79
79
|
end
|
80
80
|
|
81
81
|
let(:form) do
|
82
|
-
|
83
|
-
|
84
|
-
:address => address_class.new,
|
85
|
-
:phone_numbers_form_initializer => lambda { { :phone => phone_class.new } }
|
86
|
-
)
|
82
|
+
form_class.phone_number_initializer = lambda { {:phone => phone_class.new} }
|
83
|
+
form_model = form_class.new( :user => user_class.new, :address => address_class.new)
|
87
84
|
form_model.build_phone_number
|
88
85
|
form_model
|
89
86
|
end
|
data/spec/form/nested_spec.rb
CHANGED
@@ -9,13 +9,13 @@ describe FreeForm::Nested do
|
|
9
9
|
klass = Class.new(Module) do
|
10
10
|
include FreeForm::Property
|
11
11
|
include FreeForm::Nested
|
12
|
-
|
13
|
-
has_many :mailing_addresses do
|
12
|
+
|
13
|
+
has_many :mailing_addresses, :class_initializer => :mailing_address_initializer do
|
14
14
|
declared_model :address
|
15
15
|
|
16
|
-
property :street, :on => :address
|
16
|
+
property :street, :on => :address
|
17
17
|
end
|
18
|
-
|
18
|
+
|
19
19
|
def initialize(h={})
|
20
20
|
h.each {|k,v| send("#{k}=",v)}
|
21
21
|
end
|
@@ -28,9 +28,8 @@ describe FreeForm::Nested do
|
|
28
28
|
end
|
29
29
|
|
30
30
|
let(:form) do
|
31
|
-
|
32
|
-
|
33
|
-
)
|
31
|
+
form_class.mailing_address_initializer = lambda { { :address => OpenStruct.new } }
|
32
|
+
form_model = form_class.new
|
34
33
|
end
|
35
34
|
|
36
35
|
describe "form class" do
|
@@ -53,7 +52,8 @@ describe FreeForm::Nested do
|
|
53
52
|
|
54
53
|
it "builds unique models" do
|
55
54
|
# Using module here, since they initialize uniquely
|
56
|
-
|
55
|
+
form_class.mailing_address_initializer = lambda { { :address => Module.new } }
|
56
|
+
form = form_class.new
|
57
57
|
form.build_mailing_address
|
58
58
|
form.build_mailing_address
|
59
59
|
address_1 = form.mailing_addresses.first.address
|
@@ -61,6 +61,12 @@ describe FreeForm::Nested do
|
|
61
61
|
address_1.should_not eq(address_2)
|
62
62
|
end
|
63
63
|
|
64
|
+
it "builds initialized models through reflection on association" do
|
65
|
+
form_class.mailing_address_initializer = lambda { { :address => Module.new } }
|
66
|
+
klass = form_class.reflect_on_association(:mailing_addresses).klass
|
67
|
+
klass.new.address.should be_a(Module)
|
68
|
+
end
|
69
|
+
|
64
70
|
it "allows nested_forms to be built with custom initializers" do
|
65
71
|
form.build_mailing_address(:address => OpenStruct.new(:street => "1600 Pennsylvania Ave."))
|
66
72
|
form.mailing_addresses.first.street.should eq("1600 Pennsylvania Ave.")
|
@@ -46,12 +46,16 @@ describe FreeForm::Validation do
|
|
46
46
|
property :username, :on => :user
|
47
47
|
validates :username, :presence => true
|
48
48
|
|
49
|
-
nested_form :addresses do
|
49
|
+
nested_form :addresses, :class_initializer => :address_initializer do
|
50
50
|
declared_model :address
|
51
51
|
|
52
52
|
property :street, :on => :address
|
53
53
|
end
|
54
54
|
|
55
|
+
def self.address_initializer
|
56
|
+
{:address => OpenStruct.new}
|
57
|
+
end
|
58
|
+
|
55
59
|
def initialize(h={})
|
56
60
|
h.each {|k,v| send("#{k}=",v)}
|
57
61
|
end
|
@@ -64,10 +68,8 @@ describe FreeForm::Validation do
|
|
64
68
|
end
|
65
69
|
|
66
70
|
let(:form) do
|
67
|
-
test_form = form_class.new(
|
68
|
-
|
69
|
-
:address_form_initializer => lambda { { :address => address } } )
|
70
|
-
test_form.build_address
|
71
|
+
test_form = form_class.new(:user => user)
|
72
|
+
test_form.build_address(:address => address)
|
71
73
|
test_form
|
72
74
|
end
|
73
75
|
|
@@ -100,7 +102,7 @@ describe FreeForm::Validation do
|
|
100
102
|
property :form_property
|
101
103
|
validates :form_property, :presence => true
|
102
104
|
|
103
|
-
nested_form :addresses do
|
105
|
+
nested_form :addresses, :class_initializer => :address_initializer do
|
104
106
|
include ActiveModel::Validations
|
105
107
|
include FreeForm::Property
|
106
108
|
include FreeForm::Nested
|
@@ -112,6 +114,10 @@ describe FreeForm::Validation do
|
|
112
114
|
property :city, :on => :address
|
113
115
|
end
|
114
116
|
|
117
|
+
def self.address_initializer
|
118
|
+
{:address => OpenStruct.new}
|
119
|
+
end
|
120
|
+
|
115
121
|
def initialize(h={})
|
116
122
|
h.each {|k,v| send("#{k}=",v)}
|
117
123
|
end
|
@@ -124,10 +130,8 @@ describe FreeForm::Validation do
|
|
124
130
|
end
|
125
131
|
|
126
132
|
let(:form) do
|
127
|
-
test_form = form_class.new(
|
128
|
-
|
129
|
-
:address_form_initializer => lambda { { :address => address } } )
|
130
|
-
test_form.build_address
|
133
|
+
test_form = form_class.new( :user => user )
|
134
|
+
test_form.build_address( :address => address )
|
131
135
|
test_form
|
132
136
|
end
|
133
137
|
|