justinfrench-formtastic 0.1.1 → 0.1.2
Sign up to get free protection for your applications and to get access to all the features.
- data/README.textile +21 -3
- data/lib/formtastic.rb +63 -4
- data/spec/formtastic_spec.rb +44 -5
- metadata +2 -2
data/README.textile
CHANGED
@@ -14,7 +14,7 @@ One day, I finally had enough, so I opened up my text editor, and wrote a DSL fo
|
|
14
14
|
<%= form.input :body %>
|
15
15
|
<%= form.input :section %>
|
16
16
|
<%= form.input :publication_state, :as => :radio %>
|
17
|
-
<%= form.input :
|
17
|
+
<%= form.input :category %>
|
18
18
|
<%= form.input :allow_comments, :label => "Allow commenting on this article" %>
|
19
19
|
<% end %>
|
20
20
|
|
@@ -25,6 +25,11 @@ One day, I finally had enough, so I opened up my text editor, and wrote a DSL fo
|
|
25
25
|
<%= form.input :url_title, :required => false %>
|
26
26
|
<% end %>
|
27
27
|
|
28
|
+
<% form.inputs :for => :author do |author_form| %>
|
29
|
+
<%= form.input :first_name %>
|
30
|
+
<%= form.input :last_name %>
|
31
|
+
<% end %>
|
32
|
+
|
28
33
|
<% form.buttons do %>
|
29
34
|
<%= form.commit_button %>
|
30
35
|
<% end %>
|
@@ -151,13 +156,26 @@ If you want to customize the label text, or render some hint text below the fiel
|
|
151
156
|
<% end %>
|
152
157
|
</pre>
|
153
158
|
|
154
|
-
Nested forms (Rails 2.3) are also supported:
|
159
|
+
Nested forms (Rails 2.3) are also supported. You can do it in the Rails way:
|
155
160
|
|
156
161
|
<pre>
|
157
162
|
<% semantic_form_for @post do |post| %>
|
163
|
+
<%= post.inputs %>
|
164
|
+
|
158
165
|
<%= post.semantic_fields_for :author do |author| %>
|
159
|
-
<%= author.inputs %>
|
166
|
+
<%= author.inputs :first_name, :last_name %>
|
160
167
|
<%= end %>
|
168
|
+
|
169
|
+
<%= post.buttons %>
|
170
|
+
<% end %>
|
171
|
+
</pre>
|
172
|
+
|
173
|
+
Or in the formtastic way:
|
174
|
+
|
175
|
+
<pre>
|
176
|
+
<% semantic_form_for @post do |post| %>
|
177
|
+
<%= post.inputs %>
|
178
|
+
<%= post.inputs :first_name, :last_name, :for => :author %>
|
161
179
|
<%= post.buttons %>
|
162
180
|
<% end %>
|
163
181
|
</pre>
|
data/lib/formtastic.rb
CHANGED
@@ -177,18 +177,60 @@ module Formtastic #:nodoc:
|
|
177
177
|
# </ol>
|
178
178
|
# </fieldset>
|
179
179
|
# </form>
|
180
|
+
#
|
181
|
+
# === Nested attributes
|
182
|
+
#
|
183
|
+
# As in Rails, you can use semantic_fields_for to nest attributes:
|
184
|
+
#
|
185
|
+
# <% semantic_form_for @post do |form| %>
|
186
|
+
# <%= form.inputs :title, :body %>
|
187
|
+
#
|
188
|
+
# <% form.semantic_fields_for :author, @bob do |author_form| %>
|
189
|
+
# <% author_form.inputs do %>
|
190
|
+
# <%= author_form.input :first_name, :required => false %>
|
191
|
+
# <%= author_form.input :last_name %>
|
192
|
+
# <% end %>
|
193
|
+
# <% end %>
|
194
|
+
# <% end %>
|
195
|
+
#
|
196
|
+
# But this does not look formtastic! This is equivalent:
|
197
|
+
#
|
198
|
+
# <% semantic_form_for @post do |form| %>
|
199
|
+
# <%= form.inputs :title, :body %>
|
200
|
+
# <% form.inputs :for => [ :author, @bob ] do |author_form| %>
|
201
|
+
# <%= author_form.input :first_name, :required => false %>
|
202
|
+
# <%= author_form.input :last_name %>
|
203
|
+
# <% end %>
|
204
|
+
# <% end %>
|
205
|
+
#
|
206
|
+
# And if you don't need to give options to your input call, you could do it
|
207
|
+
# in just one line:
|
208
|
+
#
|
209
|
+
# <% semantic_form_for @post do |form| %>
|
210
|
+
# <%= form.inputs :title, :body %>
|
211
|
+
# <%= form.inputs :first_name, :last_name, :for => @bob %>
|
212
|
+
# <% end %>
|
213
|
+
#
|
214
|
+
# Just remember that calling inputs generates a new fieldset to wrap your
|
215
|
+
# inputs. If you have two separate models, but, semantically, on the page
|
216
|
+
# they are part of the same fieldset, you should use semantic_fields_for
|
217
|
+
# instead (just as you would do with Rails' form builder).
|
218
|
+
#
|
180
219
|
def inputs(*args, &block)
|
181
220
|
html_options = args.extract_options!
|
182
221
|
html_options[:class] ||= "inputs"
|
183
222
|
|
184
|
-
if
|
223
|
+
if fields_for_object = html_options.delete(:for)
|
224
|
+
inputs_for_nested_attributes(fields_for_object, args << html_options, &block)
|
225
|
+
elsif block_given?
|
185
226
|
field_set_and_list_wrapping(html_options, &block)
|
186
227
|
else
|
187
228
|
if args.empty?
|
188
|
-
args
|
229
|
+
args = @object.class.reflections.map { |n,_| n }
|
189
230
|
args += @object.class.content_columns.map(&:name)
|
190
231
|
end
|
191
232
|
contents = args.map { |method| input(method.to_sym) }
|
233
|
+
|
192
234
|
field_set_and_list_wrapping(html_options, contents)
|
193
235
|
end
|
194
236
|
end
|
@@ -253,6 +295,22 @@ module Formtastic #:nodoc:
|
|
253
295
|
|
254
296
|
protected
|
255
297
|
|
298
|
+
# Deals with :for option when it's supplied to inputs methods.
|
299
|
+
# It should raise an error if a block with arity zero is given.
|
300
|
+
#
|
301
|
+
def inputs_for_nested_attributes(fields_for_object, inputs_args, &block)
|
302
|
+
fields_for_block = if block_given?
|
303
|
+
raise ArgumentError, 'You gave :for option with a block to inputs method, ' <<
|
304
|
+
'but the block does not accept any argument.' if block.arity <= 0
|
305
|
+
|
306
|
+
proc { |f| f.inputs(*inputs_args){ block.call(f) } }
|
307
|
+
else
|
308
|
+
proc { |f| f.inputs(*inputs_args) }
|
309
|
+
end
|
310
|
+
|
311
|
+
semantic_fields_for(*Array(fields_for_object), &fields_for_block)
|
312
|
+
end
|
313
|
+
|
256
314
|
# Ensure :object => @object is set before sending the options down to the Rails layer.
|
257
315
|
# Also remove any Formtastic-specific options
|
258
316
|
def set_options(options)
|
@@ -650,12 +708,12 @@ module Formtastic #:nodoc:
|
|
650
708
|
# <li class="boolean_radio required" id="post_public_input">
|
651
709
|
# <fieldset><legend><span>make this sucker public?<abbr title="required">*</abbr></span></legend>
|
652
710
|
# <ol>
|
653
|
-
# <li>
|
711
|
+
# <li class="true">
|
654
712
|
# <label for="post_public_true">
|
655
713
|
# <input id="post_public_true" name="post[public]" type="radio" value="true" /> Yeah!
|
656
714
|
# </label>
|
657
715
|
# </li>
|
658
|
-
# <li>
|
716
|
+
# <li class="false">
|
659
717
|
# <label for="post_public_false">
|
660
718
|
# <input id="post_public_false" name="post[public]" type="radio" checked="checked" /> Nah!
|
661
719
|
# </label>
|
@@ -663,6 +721,7 @@ module Formtastic #:nodoc:
|
|
663
721
|
# </ol>
|
664
722
|
# </fieldset>
|
665
723
|
# </li>
|
724
|
+
#
|
666
725
|
def boolean_radio_input(method, options)
|
667
726
|
options[:true] ||= I18n.t('yes', :default => 'Yes', :scope => [:formtastic]).send(@@label_str_method)
|
668
727
|
options[:false] ||= I18n.t('no', :default => 'No', :scope => [:formtastic]).send(@@label_str_method)
|
data/spec/formtastic_spec.rb
CHANGED
@@ -2180,20 +2180,50 @@ describe 'Formtastic' do
|
|
2180
2180
|
end
|
2181
2181
|
end
|
2182
2182
|
end
|
2183
|
+
|
2183
2184
|
it 'should render a fieldset inside the form, with a class of "inputs"' do
|
2184
2185
|
output_buffer.should have_tag("form fieldset.inputs")
|
2185
2186
|
end
|
2187
|
+
|
2186
2188
|
it 'should render an ol inside the fieldset' do
|
2187
2189
|
output_buffer.should have_tag("form fieldset.inputs ol")
|
2188
2190
|
end
|
2191
|
+
|
2189
2192
|
it 'should render the contents of the block inside the ol' do
|
2190
2193
|
output_buffer.should have_tag("form fieldset.inputs ol", /hello/)
|
2191
2194
|
end
|
2195
|
+
|
2192
2196
|
it 'should not render a legend inside the fieldset' do
|
2193
2197
|
output_buffer.should_not have_tag("form fieldset.inputs legend")
|
2194
2198
|
end
|
2195
2199
|
end
|
2196
2200
|
|
2201
|
+
describe 'when a :for option is provided' do
|
2202
|
+
it 'should render nested inputs' do
|
2203
|
+
@bob.stub!(:column_for_attribute).and_return(mock('column', :type => :string, :limit => 255))
|
2204
|
+
|
2205
|
+
semantic_form_for(@new_post) do |builder|
|
2206
|
+
builder.inputs :for => [:author, @bob] do |bob_builder|
|
2207
|
+
concat(bob_builder.input :login)
|
2208
|
+
end
|
2209
|
+
end
|
2210
|
+
|
2211
|
+
output_buffer.should have_tag("form fieldset.inputs #post_author_login")
|
2212
|
+
output_buffer.should_not have_tag("form fieldset.inputs #author_login")
|
2213
|
+
end
|
2214
|
+
|
2215
|
+
it 'should raise an error if :for and block with no argument is given' do
|
2216
|
+
semantic_form_for(@new_post) do |builder|
|
2217
|
+
proc {
|
2218
|
+
builder.inputs(:for => [:author, @bob]) do
|
2219
|
+
#
|
2220
|
+
end
|
2221
|
+
}.should raise_error(ArgumentError, 'You gave :for option with a block to inputs method, ' <<
|
2222
|
+
'but the block does not accept any argument.')
|
2223
|
+
end
|
2224
|
+
end
|
2225
|
+
end
|
2226
|
+
|
2197
2227
|
describe 'when a :name option is provided' do
|
2198
2228
|
before do
|
2199
2229
|
@legend_text = "Advanced options"
|
@@ -2203,6 +2233,7 @@ describe 'Formtastic' do
|
|
2203
2233
|
end
|
2204
2234
|
end
|
2205
2235
|
end
|
2236
|
+
|
2206
2237
|
it 'should render a fieldset inside the form' do
|
2207
2238
|
output_buffer.should have_tag("form fieldset legend", /#{@legend_text}/)
|
2208
2239
|
end
|
@@ -2218,6 +2249,7 @@ describe 'Formtastic' do
|
|
2218
2249
|
end
|
2219
2250
|
end
|
2220
2251
|
end
|
2252
|
+
|
2221
2253
|
it 'should pass the options into the fieldset tag as attributes' do
|
2222
2254
|
output_buffer.should have_tag("form fieldset##{@id_option}")
|
2223
2255
|
output_buffer.should have_tag("form fieldset.#{@class_option}")
|
@@ -2243,7 +2275,6 @@ describe 'Formtastic' do
|
|
2243
2275
|
end
|
2244
2276
|
|
2245
2277
|
describe 'with no args' do
|
2246
|
-
|
2247
2278
|
before do
|
2248
2279
|
semantic_form_for(@new_post) do |builder|
|
2249
2280
|
concat(builder.inputs)
|
@@ -2281,11 +2312,9 @@ describe 'Formtastic' do
|
|
2281
2312
|
it 'should render a select list item for author_id' do
|
2282
2313
|
output_buffer.should have_tag('form > fieldset.inputs > ol > li.select')
|
2283
2314
|
end
|
2284
|
-
|
2285
2315
|
end
|
2286
2316
|
|
2287
2317
|
describe 'with column names as args' do
|
2288
|
-
|
2289
2318
|
before do
|
2290
2319
|
semantic_form_for(@new_post) do |builder|
|
2291
2320
|
concat(builder.inputs(:title, :body))
|
@@ -2297,11 +2326,22 @@ describe 'Formtastic' do
|
|
2297
2326
|
output_buffer.should have_tag('form > fieldset.inputs > ol > li.string')
|
2298
2327
|
output_buffer.should have_tag('form > fieldset.inputs > ol > li.text')
|
2299
2328
|
end
|
2329
|
+
end
|
2300
2330
|
|
2331
|
+
describe 'when a :for option is provided' do
|
2332
|
+
it 'should render nested inputs' do
|
2333
|
+
@bob.stub!(:column_for_attribute).and_return(mock('column', :type => :string, :limit => 255))
|
2334
|
+
|
2335
|
+
semantic_form_for(@new_post) do |builder|
|
2336
|
+
concat(builder.inputs :login, :for => @bob)
|
2337
|
+
end
|
2338
|
+
|
2339
|
+
output_buffer.should have_tag("form fieldset.inputs #post_author_login")
|
2340
|
+
output_buffer.should_not have_tag("form fieldset.inputs #author_login")
|
2341
|
+
end
|
2301
2342
|
end
|
2302
2343
|
|
2303
2344
|
describe 'with column names and an options hash as args' do
|
2304
|
-
|
2305
2345
|
before do
|
2306
2346
|
semantic_form_for(@new_post) do |builder|
|
2307
2347
|
concat(builder.inputs(:title, :body, :name => "Legendary Legend Text", :id => "my-id"))
|
@@ -2319,7 +2359,6 @@ describe 'Formtastic' do
|
|
2319
2359
|
it 'should use the special :name option as a text for the legend tag' do
|
2320
2360
|
output_buffer.should have_tag('form > fieldset#my-id.inputs > legend', /Legendary Legend Text/)
|
2321
2361
|
end
|
2322
|
-
|
2323
2362
|
end
|
2324
2363
|
|
2325
2364
|
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: justinfrench-formtastic
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.1.
|
4
|
+
version: 0.1.2
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Justin French
|
@@ -9,7 +9,7 @@ autorequire: formtastic
|
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
11
|
|
12
|
-
date: 2009-03-
|
12
|
+
date: 2009-03-17 00:00:00 -07:00
|
13
13
|
default_executable:
|
14
14
|
dependencies: []
|
15
15
|
|