justinfrench-formtastic 0.1.1 → 0.1.2

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.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 :author %>
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 block_given?
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 = @object.class.reflections.map { |n,_| n }
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)
@@ -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.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-09 00:00:00 -07:00
12
+ date: 2009-03-17 00:00:00 -07:00
13
13
  default_executable:
14
14
  dependencies: []
15
15