freeform 0.0.3.rc1 → 0.0.3.rc2
Sign up to get free protection for your applications and to get access to all the features.
- 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
|
|