formtastic 0.9.8 → 0.9.9

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
@@ -206,7 +206,7 @@ When working in has many association, you can even supply @"%i"@ in your fieldse
206
206
  </pre>
207
207
 
208
208
 
209
- Customize HTML attributes for any input using the @:input_html@ option. Typically his is used to disable the input, change the size of a text field, change the rows in a textarea, or even to add a special class to an input to attach special behavior like "autogrow":http://plugins.jquery.com/project/autogrow textareas:
209
+ Customize HTML attributes for any input using the @:input_html@ option. Typically this is used to disable the input, change the size of a text field, change the rows in a textarea, or even to add a special class to an input to attach special behavior like "autogrow":http://plugins.jquery.com/project/autogrow textareas:
210
210
 
211
211
  <pre>
212
212
  <% semantic_form_for @post do |form| %>
@@ -337,7 +337,7 @@ Formtastic supports localized *labels*, *hints*, *legends*, *actions* using the
337
337
  title: "Choose a good title for you post."
338
338
  body: "Write something inspiring here."
339
339
  actions:
340
- create: "Create my {{model}}"
340
+ create: "Create my %{model}"
341
341
  update: "Save changes"
342
342
  dummie: "Launch!"
343
343
  </pre>
@@ -354,7 +354,7 @@ Formtastic supports localized *labels*, *hints*, *legends*, *actions* using the
354
354
  <%= form.input :section %> # => :label => I18n.t('activerecord.attributes.user.section') or 'Section'
355
355
  <% end %>
356
356
  <% form.buttons do %>
357
- <%= form.commit_button %> # => "Create my {{model}}"
357
+ <%= form.commit_button %> # => "Create my %{model}"
358
358
  <% end %>
359
359
  <% end %>
360
360
  </pre>
@@ -28,7 +28,7 @@
28
28
  # Formtastic::SemanticFormBuilder.inline_errors = :sentence
29
29
 
30
30
  # Set the method to call on label text to transform or format it for human-friendly
31
- # reading when formtastic is user without object. Defaults to :humanize.
31
+ # reading when formtastic is used without object. Defaults to :humanize.
32
32
  # Formtastic::SemanticFormBuilder.label_str_method = :humanize
33
33
 
34
34
  # Set the array of methods to try calling on parent objects in :select and :radio inputs
data/lib/formtastic.rb CHANGED
@@ -1,5 +1,6 @@
1
1
  # coding: utf-8
2
2
  require File.join(File.dirname(__FILE__), *%w[formtastic i18n])
3
+ require File.join(File.dirname(__FILE__), *%w[formtastic util])
3
4
 
4
5
  module Formtastic #:nodoc:
5
6
 
@@ -9,7 +10,7 @@ module Formtastic #:nodoc:
9
10
  @@default_text_area_height = 20
10
11
  @@all_fields_required_by_default = true
11
12
  @@include_blank_for_select_by_default = true
12
- @@required_string = proc { %{<abbr title="#{::Formtastic::I18n.t(:required)}">*</abbr>} }
13
+ @@required_string = proc { ::Formtastic::Util.html_safe(%{<abbr title="#{::Formtastic::I18n.t(:required)}">*</abbr>}) }
13
14
  @@optional_string = ''
14
15
  @@inline_errors = :sentence
15
16
  @@label_str_method = :humanize
@@ -105,7 +106,7 @@ module Formtastic #:nodoc:
105
106
  send(:"inline_#{type}_for", method, options)
106
107
  end.compact.join("\n")
107
108
 
108
- return template.content_tag(:li, list_item_content, wrapper_html)
109
+ return template.content_tag(:li, Formtastic::Util.html_safe(list_item_content), wrapper_html)
109
110
  end
110
111
 
111
112
  # Creates an input fieldset and ol tag wrapping for use around a set of inputs. It can be
@@ -342,7 +343,7 @@ module Formtastic #:nodoc:
342
343
  element_class = ['commit', options.delete(:class)].compact.join(' ') # TODO: Add class reflecting on form action.
343
344
  accesskey = (options.delete(:accesskey) || @@default_commit_button_accesskey) unless button_html.has_key?(:accesskey)
344
345
  button_html = button_html.merge(:accesskey => accesskey) if accesskey
345
- template.content_tag(:li, self.submit(text, button_html), :class => element_class)
346
+ template.content_tag(:li, Formtastic::Util.html_safe(self.submit(text, button_html)), :class => element_class)
346
347
  end
347
348
 
348
349
  # A thin wrapper around #fields_for to set :builder => Formtastic::SemanticFormBuilder
@@ -399,11 +400,15 @@ module Formtastic #:nodoc:
399
400
  text = options_or_text
400
401
  options ||= {}
401
402
  end
403
+
402
404
  text = localized_string(method, text, :label) || humanized_attribute_name(method)
403
405
  text += required_or_optional_string(options.delete(:required))
406
+ text = Formtastic::Util.html_safe(text)
404
407
 
405
408
  # special case for boolean (checkbox) labels, which have a nested input
406
- text = (options.delete(:label_prefix_for_nested_input) || "") + text
409
+ if options.key?(:label_prefix_for_nested_input)
410
+ text = options.delete(:label_prefix_for_nested_input) + text
411
+ end
407
412
 
408
413
  input_name = options.delete(:input_name) || method
409
414
  super(input_name, text, options)
@@ -422,8 +427,10 @@ module Formtastic #:nodoc:
422
427
  #
423
428
  def inline_errors_for(method, options = nil) #:nodoc:
424
429
  if render_inline_errors?
425
- errors = @object.errors[method.to_sym]
426
- send(:"error_#{@@inline_errors}", [*errors]) if errors.present?
430
+ errors = [@object.errors[method.to_sym]]
431
+ errors << [@object.errors[association_primary_key(method)]] if association_macro_for_method(method) == :belongs_to
432
+ errors = errors.flatten.compact.uniq
433
+ send(:"error_#{@@inline_errors}", [*errors]) if errors.any?
427
434
  else
428
435
  nil
429
436
  end
@@ -452,7 +459,7 @@ module Formtastic #:nodoc:
452
459
  return nil if full_errors.blank?
453
460
  html_options[:class] ||= "errors"
454
461
  template.content_tag(:ul, html_options) do
455
- full_errors.map { |error| template.content_tag(:li, error) }.join
462
+ Formtastic::Util.html_safe(full_errors.map { |error| template.content_tag(:li, Formtastic::Util.html_safe(error)) }.join)
456
463
  end
457
464
  end
458
465
 
@@ -483,6 +490,18 @@ module Formtastic #:nodoc:
483
490
  []
484
491
  end
485
492
  end
493
+
494
+ # Returns nil, or a symbol like :belongs_to or :has_many
495
+ def association_macro_for_method(method) #:nodoc:
496
+ reflection = self.reflection_for(method)
497
+ reflection.macro if reflection
498
+ end
499
+
500
+ def association_primary_key(method)
501
+ reflection = self.reflection_for(method)
502
+ reflection.options[:foreign_key] if reflection && !reflection.options[:foreign_key].blank?
503
+ :"#{method}_id"
504
+ end
486
505
 
487
506
  # Prepare options to be sent to label
488
507
  #
@@ -504,9 +523,9 @@ module Formtastic #:nodoc:
504
523
  raise ArgumentError, 'You gave :for option with a block to inputs method, ' <<
505
524
  'but the block does not accept any argument.' if block.arity <= 0
506
525
 
507
- proc { |f| f.inputs(*args){ block.call(f) } }
526
+ proc { |f| return f.inputs(*args){ block.call(f) } }
508
527
  else
509
- proc { |f| f.inputs(*args) }
528
+ proc { |f| return f.inputs(*args) }
510
529
  end
511
530
 
512
531
  fields_for_args = [options.delete(:for), options.delete(:for_options) || {}].flatten
@@ -859,12 +878,12 @@ module Formtastic #:nodoc:
859
878
  html_options[:checked] = selected_value == value if selected_option_is_present
860
879
 
861
880
  li_content = template.content_tag(:label,
862
- "#{self.radio_button(input_name, value, html_options)} #{label}",
881
+ Formtastic::Util.html_safe("#{self.radio_button(input_name, value, html_options)} #{label}"),
863
882
  :for => input_id
864
883
  )
865
884
 
866
885
  li_options = value_as_class ? { :class => [method.to_s.singularize, value.to_s.downcase].join('_') } : {}
867
- template.content_tag(:li, li_content, li_options)
886
+ template.content_tag(:li, Formtastic::Util.html_safe(li_content), li_options)
868
887
  end
869
888
 
870
889
  field_set_and_list_wrapping_for_method(method, options, list_item_content)
@@ -994,8 +1013,8 @@ module Formtastic #:nodoc:
994
1013
  list_items_capture = ""
995
1014
  hidden_fields_capture = ""
996
1015
 
997
- datetime = options.key?(:selected) ? options[:selected] : Time.now # can't do an || because nil is an important value
998
- datetime = @object.send(method) if @object && @object.send(method) # object trumps :selected
1016
+ datetime = options[:selected]
1017
+ datetime = @object.send(method) if @object && @object.send(method) # object value trumps :selected value
999
1018
 
1000
1019
  html_options = options.delete(:input_html) || {}
1001
1020
  input_ids = []
@@ -1013,10 +1032,10 @@ module Formtastic #:nodoc:
1013
1032
  opts = strip_formtastic_options(options).merge(:prefix => @object_name, :field_name => field_name, :default => datetime)
1014
1033
  item_label_text = labels[input] || ::I18n.t(input.to_s, :default => input.to_s.humanize, :scope => [:datetime, :prompts])
1015
1034
 
1016
- list_items_capture << template.content_tag(:li, [
1017
- !item_label_text.blank? ? template.content_tag(:label, item_label_text, :for => input_id) : "",
1035
+ list_items_capture << template.content_tag(:li, Formtastic::Util.html_safe([
1036
+ !item_label_text.blank? ? template.content_tag(:label, Formtastic::Util.html_safe(item_label_text), :for => input_id) : "",
1018
1037
  template.send(:"select_#{input}", datetime, opts, html_options.merge(:id => input_id))
1019
- ].join("")
1038
+ ].join(""))
1020
1039
  )
1021
1040
  end
1022
1041
  end
@@ -1110,7 +1129,10 @@ module Formtastic #:nodoc:
1110
1129
  selected_option_is_present = [:selected, :checked].any? { |k| options.key?(k) }
1111
1130
  selected_values = (options.key?(:checked) ? options[:checked] : options[:selected]) if selected_option_is_present
1112
1131
  selected_values = [*selected_values].compact
1113
-
1132
+
1133
+ disabled_option_is_present = options.key?(:disabled)
1134
+ disabled_values = [*options[:disabled]] if disabled_option_is_present
1135
+
1114
1136
  list_item_content = collection.map do |c|
1115
1137
  label = c.is_a?(Array) ? c.first : c
1116
1138
  value = c.is_a?(Array) ? c.last : c
@@ -1118,15 +1140,16 @@ module Formtastic #:nodoc:
1118
1140
  input_ids << input_id
1119
1141
 
1120
1142
  html_options[:checked] = selected_values.include?(value) if selected_option_is_present
1143
+ html_options[:disabled] = disabled_values.include?(value) if disabled_option_is_present
1121
1144
  html_options[:id] = input_id
1122
1145
 
1123
1146
  li_content = template.content_tag(:label,
1124
- "#{self.check_box(input_name, html_options, value, unchecked_value)} #{label}",
1147
+ Formtastic::Util.html_safe("#{self.check_box(input_name, html_options, value, unchecked_value)} #{label}"),
1125
1148
  :for => input_id
1126
1149
  )
1127
1150
 
1128
1151
  li_options = value_as_class ? { :class => [method.to_s.singularize, value.to_s.downcase].join('_') } : {}
1129
- template.content_tag(:li, li_content, li_options)
1152
+ template.content_tag(:li, Formtastic::Util.html_safe(li_content), li_options)
1130
1153
  end
1131
1154
 
1132
1155
  field_set_and_list_wrapping_for_method(method, options, list_item_content)
@@ -1191,13 +1214,13 @@ module Formtastic #:nodoc:
1191
1214
  def inline_hints_for(method, options) #:nodoc:
1192
1215
  options[:hint] = localized_string(method, options[:hint], :hint)
1193
1216
  return if options[:hint].blank?
1194
- template.content_tag(:p, options[:hint], :class => 'inline-hints')
1217
+ template.content_tag(:p, Formtastic::Util.html_safe(options[:hint]), :class => 'inline-hints')
1195
1218
  end
1196
1219
 
1197
1220
  # Creates an error sentence by calling to_sentence on the errors array.
1198
1221
  #
1199
1222
  def error_sentence(errors) #:nodoc:
1200
- template.content_tag(:p, errors.to_sentence.untaint, :class => 'inline-errors')
1223
+ template.content_tag(:p, Formtastic::Util.html_safe(errors.to_sentence.untaint), :class => 'inline-errors')
1201
1224
  end
1202
1225
 
1203
1226
  # Creates an error li list.
@@ -1205,15 +1228,15 @@ module Formtastic #:nodoc:
1205
1228
  def error_list(errors) #:nodoc:
1206
1229
  list_elements = []
1207
1230
  errors.each do |error|
1208
- list_elements << template.content_tag(:li, error.untaint)
1231
+ list_elements << template.content_tag(:li, Formtastic::Util.html_safe(error.untaint))
1209
1232
  end
1210
- template.content_tag(:ul, list_elements.join("\n"), :class => 'errors')
1233
+ template.content_tag(:ul, Formtastic::Util.html_safe(list_elements.join("\n")), :class => 'errors')
1211
1234
  end
1212
1235
 
1213
1236
  # Creates an error sentence containing only the first error
1214
1237
  #
1215
1238
  def error_first(errors) #:nodoc:
1216
- template.content_tag(:p, errors.first.untaint, :class => 'inline-errors')
1239
+ template.content_tag(:p, Formtastic::Util.html_safe(errors.first.untaint), :class => 'inline-errors')
1217
1240
  end
1218
1241
 
1219
1242
  # Generates the required or optional string. If the value set is a proc,
@@ -1260,7 +1283,7 @@ module Formtastic #:nodoc:
1260
1283
 
1261
1284
  legend = html_options.delete(:name).to_s
1262
1285
  legend %= parent_child_index(html_options[:parent]) if html_options[:parent]
1263
- legend = template.content_tag(:legend, template.content_tag(:span, legend)) unless legend.blank?
1286
+ legend = template.content_tag(:legend, template.content_tag(:span, Formtastic::Util.html_safe(legend))) unless legend.blank?
1264
1287
 
1265
1288
  if block_given?
1266
1289
  contents = if template.respond_to?(:is_haml?) && template.is_haml?
@@ -1273,11 +1296,11 @@ module Formtastic #:nodoc:
1273
1296
  # Ruby 1.9: String#to_s behavior changed, need to make an explicit join.
1274
1297
  contents = contents.join if contents.respond_to?(:join)
1275
1298
  fieldset = template.content_tag(:fieldset,
1276
- legend << template.content_tag(:ol, contents),
1299
+ Formtastic::Util.html_safe(legend) << template.content_tag(:ol, Formtastic::Util.html_safe(contents)),
1277
1300
  html_options.except(:builder, :parent)
1278
1301
  )
1279
1302
 
1280
- template.concat(fieldset) if block_given?
1303
+ template.concat(fieldset) if block_given? && (!defined?(Rails::VERSION) || Rails::VERSION::MAJOR == 2)
1281
1304
  fieldset
1282
1305
  end
1283
1306
 
@@ -1305,7 +1328,7 @@ module Formtastic #:nodoc:
1305
1328
  template.content_tag(:legend,
1306
1329
  self.label(method, options_for_label(options).merge(:for => options.delete(:label_for))), :class => 'label'
1307
1330
  ) <<
1308
- template.content_tag(:ol, contents)
1331
+ template.content_tag(:ol, Formtastic::Util.html_safe(contents))
1309
1332
  )
1310
1333
  end
1311
1334
 
@@ -1323,7 +1346,7 @@ module Formtastic #:nodoc:
1323
1346
  case column.type
1324
1347
  when :string
1325
1348
  return :password if method.to_s =~ /password/
1326
- return :country if method.to_s =~ /country/
1349
+ return :country if method.to_s =~ /country$/
1327
1350
  return :time_zone if method.to_s =~ /time_zone/
1328
1351
  when :integer
1329
1352
  return :select if method.to_s =~ /_id$/
@@ -1380,7 +1403,13 @@ module Formtastic #:nodoc:
1380
1403
  collection = if options[:collection]
1381
1404
  options.delete(:collection)
1382
1405
  elsif reflection = self.reflection_for(column)
1383
- reflection.klass.find(:all, options[:find_options] || {})
1406
+ options[:find_options] ||= {}
1407
+
1408
+ if conditions = reflection.options[:conditions]
1409
+ options[:find_options][:conditions] = reflection.klass.merge_conditions(conditions, options[:find_options][:conditions])
1410
+ end
1411
+
1412
+ reflection.klass.find(:all, options[:find_options])
1384
1413
  else
1385
1414
  create_boolean_collection(options)
1386
1415
  end
@@ -1471,7 +1500,7 @@ module Formtastic #:nodoc:
1471
1500
  if [:has_and_belongs_to_many, :has_many].include?(reflection.macro)
1472
1501
  "#{method.to_s.singularize}_ids"
1473
1502
  else
1474
- reflection.options[:foreign_key] || reflection.options[:class_name].try(:foreign_key) || "#{method}_id"
1503
+ reflection.options[:foreign_key] || "#{method}_id"
1475
1504
  end
1476
1505
  else
1477
1506
  method
@@ -1566,9 +1595,9 @@ module Formtastic #:nodoc:
1566
1595
  #
1567
1596
  # Lookup priority:
1568
1597
  #
1569
- # 'formtastic.{{type}}.{{model}}.{{action}}.{{attribute}}'
1570
- # 'formtastic.{{type}}.{{model}}.{{attribute}}'
1571
- # 'formtastic.{{type}}.{{attribute}}'
1598
+ # 'formtastic.%{type}.%{model}.%{action}.%{attribute}'
1599
+ # 'formtastic.%{type}.%{model}.%{attribute}'
1600
+ # 'formtastic.%{type}.%{attribute}'
1572
1601
  #
1573
1602
  # Example:
1574
1603
  #
@@ -1587,15 +1616,16 @@ module Formtastic #:nodoc:
1587
1616
  use_i18n = value.nil? ? @@i18n_lookups_by_default : (value != false)
1588
1617
 
1589
1618
  if use_i18n
1590
- model_name = self.model_name.underscore
1619
+ model_name, nested_model_name = normalize_model_name(self.model_name.underscore)
1591
1620
  action_name = template.params[:action].to_s rescue ''
1592
1621
  attribute_name = key.to_s
1593
1622
 
1594
1623
  defaults = ::Formtastic::I18n::SCOPES.collect do |i18n_scope|
1595
1624
  i18n_path = i18n_scope.dup
1596
- i18n_path.gsub!('{{action}}', action_name)
1597
- i18n_path.gsub!('{{model}}', model_name)
1598
- i18n_path.gsub!('{{attribute}}', attribute_name)
1625
+ i18n_path.gsub!('%{action}', action_name)
1626
+ i18n_path.gsub!('%{model}', model_name)
1627
+ i18n_path.gsub!('%{nested_model}', nested_model_name) unless nested_model_name.nil?
1628
+ i18n_path.gsub!('%{attribute}', attribute_name)
1599
1629
  i18n_path.gsub!('..', '.')
1600
1630
  i18n_path.to_sym
1601
1631
  end
@@ -1612,6 +1642,14 @@ module Formtastic #:nodoc:
1612
1642
  @object.present? ? @object.class.name : @object_name.to_s.classify
1613
1643
  end
1614
1644
 
1645
+ def normalize_model_name(name)
1646
+ if name =~ /(.+)\[(.+)\]/
1647
+ [$1, $2]
1648
+ else
1649
+ [name]
1650
+ end
1651
+ end
1652
+
1615
1653
  def send_or_call(duck, object)
1616
1654
  if duck.is_a?(Proc)
1617
1655
  duck.call(object)
@@ -1,3 +1,4 @@
1
+ # coding: utf-8
1
2
  module Formtastic
2
3
  module I18n
3
4
 
@@ -6,13 +7,16 @@ module Formtastic
6
7
  :required => 'required',
7
8
  :yes => 'Yes',
8
9
  :no => 'No',
9
- :create => 'Create {{model}}',
10
- :update => 'Update {{model}}'
10
+ :create => 'Create %{model}',
11
+ :update => 'Update %{model}'
11
12
  }.freeze
12
13
  SCOPES = [
13
- '{{model}}.{{action}}.{{attribute}}',
14
- '{{model}}.{{attribute}}',
15
- '{{attribute}}'
14
+ '%{model}.%{nested_model}.%{action}.%{attribute}',
15
+ '%{model}.%{action}.%{attribute}',
16
+ '%{model}.%{nested_model}.%{attribute}',
17
+ '%{model}.%{attribute}',
18
+ '%{nested_model}.%{attribute}',
19
+ '%{attribute}'
16
20
  ]
17
21
 
18
22
  class << self
@@ -1,3 +1,4 @@
1
+ # coding: utf-8
1
2
  module Formtastic
2
3
  module LayoutHelper
3
4
 
@@ -0,0 +1,25 @@
1
+ # Adapted from the rails3 compatibility shim in Haml 2.2
2
+ module Formtastic
3
+ module Util
4
+ extend self
5
+ ## Rails XSS Safety
6
+
7
+ # Returns the given text, marked as being HTML-safe.
8
+ # With older versions of the Rails XSS-safety mechanism,
9
+ # this destructively modifies the HTML-safety of `text`.
10
+ #
11
+ # @param text [String]
12
+ # @return [String] `text`, marked as HTML-safe
13
+ def html_safe(text)
14
+ return text if text.nil?
15
+ return text.html_safe if defined?(ActiveSupport::SafeBuffer)
16
+ return text.html_safe!
17
+ end
18
+
19
+ def rails_safe_buffer_class
20
+ return ActionView::SafeBuffer if defined?(ActionView::SafeBuffer)
21
+ ActiveSupport::SafeBuffer
22
+ end
23
+
24
+ end
25
+ end
@@ -136,11 +136,11 @@ describe 'SemanticFormBuilder#commit_button' do
136
136
  describe 'when no explicit label is provided' do
137
137
  describe 'when no I18n-localized label is provided' do
138
138
  before do
139
- ::I18n.backend.store_translations :en, :formtastic => {:submit => 'Submit {{model}}'}
139
+ ::I18n.backend.store_translations :en, :formtastic => {:submit => 'Submit %{model}'}
140
140
  end
141
141
 
142
142
  after do
143
- ::I18n.backend.store_translations :en, :formtastic => {:submit => nil}
143
+ ::I18n.backend.reload!
144
144
  end
145
145
 
146
146
  it 'should render an input with default I18n-localized label (fallback)' do
@@ -157,33 +157,34 @@ describe 'SemanticFormBuilder#commit_button' do
157
157
  :formtastic => {
158
158
  :actions => {
159
159
  :submit => 'Custom Submit',
160
- :post => {
161
- :submit => 'Custom Submit {{model}}'
162
- }
163
160
  }
164
161
  }
165
162
  ::Formtastic::SemanticFormBuilder.i18n_lookups_by_default = true
166
163
  end
167
164
 
168
- it 'should render an input with localized label (I18n)' do
169
- semantic_form_for(:post, :url => 'http://example.com') do |builder|
170
- concat(builder.commit_button)
171
- end
172
- output_buffer.should have_tag(%Q{li.commit input[@value="Custom Submit Post"][@class~="submit"]})
165
+ after do
166
+ ::I18n.backend.reload!
173
167
  end
174
168
 
175
- it 'should render an input with anoptional localized label (I18n) - if first is not set' do
169
+ it 'should render an input with localized label (I18n)' do
176
170
  ::I18n.backend.store_translations :en,
177
171
  :formtastic => {
178
172
  :actions => {
179
173
  :post => {
180
- :submit => nil
174
+ :submit => 'Custom Submit %{model}'
181
175
  }
182
176
  }
183
177
  }
184
178
  semantic_form_for(:post, :url => 'http://example.com') do |builder|
185
179
  concat(builder.commit_button)
186
180
  end
181
+ output_buffer.should have_tag(%Q{li.commit input[@value="Custom Submit Post"][@class~="submit"]})
182
+ end
183
+
184
+ it 'should render an input with anoptional localized label (I18n) - if first is not set' do
185
+ semantic_form_for(:post, :url => 'http://example.com') do |builder|
186
+ concat(builder.commit_button)
187
+ end
187
188
  output_buffer.should have_tag(%Q{li.commit input[@value="Custom Submit"][@class~="submit"]})
188
189
  end
189
190
 
@@ -209,11 +210,11 @@ describe 'SemanticFormBuilder#commit_button' do
209
210
  describe 'when no explicit label is provided' do
210
211
  describe 'when no I18n-localized label is provided' do
211
212
  before do
212
- ::I18n.backend.store_translations :en, :formtastic => {:create => 'Create {{model}}'}
213
+ ::I18n.backend.store_translations :en, :formtastic => {:create => 'Create %{model}'}
213
214
  end
214
215
 
215
216
  after do
216
- ::I18n.backend.store_translations :en, :formtastic => {:create => nil}
217
+ ::I18n.backend.reload!
217
218
  end
218
219
 
219
220
  it 'should render an input with default I18n-localized label (fallback)' do
@@ -230,40 +231,35 @@ describe 'SemanticFormBuilder#commit_button' do
230
231
  :formtastic => {
231
232
  :actions => {
232
233
  :create => 'Custom Create',
233
- :post => {
234
- :create => 'Custom Create {{model}}'
235
- }
236
234
  }
237
235
  }
238
236
  ::Formtastic::SemanticFormBuilder.i18n_lookups_by_default = true
239
237
  end
240
238
 
241
239
  after do
242
- ::I18n.backend.store_translations :en, :formtastic => nil
240
+ ::I18n.backend.reload!
243
241
  end
244
242
 
245
243
  it 'should render an input with localized label (I18n)' do
246
- semantic_form_for(@new_post) do |builder|
247
- concat(builder.commit_button)
248
- end
249
- output_buffer.should have_tag(%Q{li.commit input[@value="Custom Create Post"][@class~="create"]})
250
- end
251
-
252
- it 'should render an input with anoptional localized label (I18n) - if first is not set' do
253
244
  ::I18n.backend.store_translations :en,
254
245
  :formtastic => {
255
246
  :actions => {
256
247
  :post => {
257
- :create => nil
248
+ :create => 'Custom Create %{model}'
258
249
  }
259
250
  }
260
251
  }
261
252
  semantic_form_for(@new_post) do |builder|
262
253
  concat(builder.commit_button)
263
254
  end
264
- output_buffer.should have_tag(%Q{li.commit input[@value="Custom Create"][@class~="create"]})
265
- ::I18n.backend.store_translations :en, :formtastic => nil
266
-
255
+ output_buffer.should have_tag(%Q{li.commit input[@value="Custom Create Post"][@class~="create"]})
256
+ end
257
+
258
+ it 'should render an input with anoptional localized label (I18n) - if first is not set' do
259
+ semantic_form_for(@new_post) do |builder|
260
+ concat(builder.commit_button)
261
+ end
262
+ output_buffer.should have_tag(%Q{li.commit input[@value="Custom Create"][@class~="create"]})
267
263
  end
268
264
 
269
265
  end
@@ -288,11 +284,11 @@ describe 'SemanticFormBuilder#commit_button' do
288
284
  describe 'when no explicit label is provided' do
289
285
  describe 'when no I18n-localized label is provided' do
290
286
  before do
291
- ::I18n.backend.store_translations :en, :formtastic => {:update => 'Save {{model}}'}
287
+ ::I18n.backend.store_translations :en, :formtastic => {:update => 'Save %{model}'}
292
288
  end
293
289
 
294
290
  after do
295
- ::I18n.backend.store_translations :en, :formtastic => {:update => nil}
291
+ ::I18n.backend.reload!
296
292
  end
297
293
 
298
294
  it 'should render an input with default I18n-localized label (fallback)' do
@@ -309,33 +305,34 @@ describe 'SemanticFormBuilder#commit_button' do
309
305
  :formtastic => {
310
306
  :actions => {
311
307
  :update => 'Custom Save',
312
- :post => {
313
- :update => 'Custom Save {{model}}'
314
- }
315
308
  }
316
309
  }
317
310
  ::Formtastic::SemanticFormBuilder.i18n_lookups_by_default = true
318
311
  end
319
312
 
320
- it 'should render an input with localized label (I18n)' do
321
- semantic_form_for(@new_post) do |builder|
322
- concat(builder.commit_button)
323
- end
324
- output_buffer.should have_tag(%Q{li.commit input[@value="Custom Save Post"][@class~="update"]})
313
+ after do
314
+ ::I18n.backend.reload!
325
315
  end
326
-
327
- it 'should render an input with anoptional localized label (I18n) - if first is not set' do
316
+
317
+ it 'should render an input with localized label (I18n)' do
328
318
  ::I18n.backend.store_translations :en,
329
319
  :formtastic => {
330
320
  :actions => {
331
321
  :post => {
332
- :update => nil
322
+ :update => 'Custom Save %{model}'
333
323
  }
334
324
  }
335
325
  }
336
326
  semantic_form_for(@new_post) do |builder|
337
327
  concat(builder.commit_button)
338
328
  end
329
+ output_buffer.should have_tag(%Q{li.commit input[@value="Custom Save Post"][@class~="update"]})
330
+ end
331
+
332
+ it 'should render an input with anoptional localized label (I18n) - if first is not set' do
333
+ semantic_form_for(@new_post) do |builder|
334
+ concat(builder.commit_button)
335
+ end
339
336
  output_buffer.should have_tag(%Q{li.commit input[@value="Custom Save"][@class~="update"]})
340
337
  ::I18n.backend.store_translations :en, :formtastic => {}
341
338
  end
data/spec/errors_spec.rb CHANGED
@@ -81,5 +81,24 @@ describe 'SemanticFormBuilder#errors_on' do
81
81
  end
82
82
  end
83
83
 
84
+
85
+ describe 'when there are errors on the association and column' do
86
+
87
+ it "should list all unique errors" do
88
+ ::Formtastic::SemanticFormBuilder.inline_errors = :list
89
+ ::Post.stub!(:reflections).and_return({:author => mock('reflection', :options => {}, :macro => :belongs_to)})
90
+
91
+ @errors.stub!(:[]).with(:author).and_return(['must not be blank'])
92
+ @errors.stub!(:[]).with(:author_id).and_return(['is already taken', 'must not be blank']) # note the duplicate of association
93
+
94
+ semantic_form_for(@new_post) do |builder|
95
+ concat(builder.input(:author))
96
+ end
97
+ output_buffer.should have_tag("ul.errors li", /must not be blank/, :count => 1)
98
+ output_buffer.should have_tag("ul.errors li", /is already taken/, :count => 1)
99
+ end
100
+
101
+ end
102
+
84
103
  end
85
104
 
data/spec/i18n_spec.rb CHANGED
@@ -24,20 +24,24 @@ describe 'Formtastic::I18n' do
24
24
 
25
25
  before do
26
26
  @formtastic_strings = {
27
- :required => 'Default Required',
28
27
  :yes => 'Default Yes',
29
28
  :no => 'Default No',
30
- :create => 'Default Create {{model}}',
31
- :update => 'Default Update {{model}}',
29
+ :create => 'Default Create %{model}',
30
+ :update => 'Default Update %{model}',
32
31
  :custom_scope => {
33
32
  :duck => 'Duck',
34
- :duck_pond => '{{ducks}} ducks in a pond'
33
+ :duck_pond => '%{ducks} ducks in a pond'
35
34
  }
36
35
  }
37
36
  ::I18n.backend.store_translations :en, :formtastic => @formtastic_strings
38
37
  end
38
+
39
+ after do
40
+ ::I18n.backend.reload!
41
+ end
39
42
 
40
43
  it "should translate core strings correctly" do
44
+ ::I18n.backend.store_translations :en, {:formtastic => {:required => 'Default Required'}}
41
45
  ::Formtastic::I18n.t(:required).should == "Default Required"
42
46
  ::Formtastic::I18n.t(:yes).should == "Default Yes"
43
47
  ::Formtastic::I18n.t(:no).should == "Default No"
@@ -54,7 +58,6 @@ describe 'Formtastic::I18n' do
54
58
  end
55
59
 
56
60
  it "should be possible to override default values" do
57
- ::I18n.backend.store_translations :en, {:formtastic => {:required => nil}}
58
61
  ::Formtastic::I18n.t(:required, :default => 'Nothing found!').should == 'Nothing found!'
59
62
  end
60
63
 
@@ -63,18 +66,12 @@ describe 'Formtastic::I18n' do
63
66
  describe "when no I18n locales are available" do
64
67
 
65
68
  before do
66
- ::I18n.backend.store_translations :en, :formtastic => {
67
- :required => nil,
68
- :yes => nil,
69
- :no => nil,
70
- :create => nil,
71
- :update => nil
72
- }
69
+ ::I18n.backend.reload!
73
70
  end
74
-
71
+
75
72
  it "should use default strings" do
76
73
  (::Formtastic::I18n::DEFAULT_VALUES.keys).each do |key|
77
- ::Formtastic::I18n.t(key, :model => '{{model}}').should == ::Formtastic::I18n::DEFAULT_VALUES[key]
74
+ ::Formtastic::I18n.t(key, :model => '%{model}').should == ::Formtastic::I18n::DEFAULT_VALUES[key]
78
75
  end
79
76
  end
80
77
 
@@ -92,7 +89,8 @@ describe 'Formtastic::I18n' do
92
89
  :labels => {
93
90
  :title => "Hello world!",
94
91
  :post => {:title => "Hello post!"},
95
- :project => {:title => "Hello project!"}
92
+ :project => {:title => "Hello project!", :task => {:name => "Hello task name!"}},
93
+ :line_item => {:name => "Hello line item name!"}
96
94
  }
97
95
  }
98
96
  ::Formtastic::SemanticFormBuilder.i18n_lookups_by_default = true
@@ -102,7 +100,7 @@ describe 'Formtastic::I18n' do
102
100
  end
103
101
 
104
102
  after do
105
- ::I18n.backend.store_translations :en, :formtastic => nil
103
+ ::I18n.backend.reload!
106
104
  ::Formtastic::SemanticFormBuilder.i18n_lookups_by_default = false
107
105
  end
108
106
 
@@ -124,6 +122,25 @@ describe 'Formtastic::I18n' do
124
122
  output_buffer.should have_tag("form label", /Hello project!/)
125
123
  end
126
124
 
125
+ it 'should be able to translate nested objects with nested translations' do
126
+ semantic_form_for(:project, :url => 'http://test.host') do |builder|
127
+ builder.semantic_fields_for(:task) do |f|
128
+ concat(f.input(:name))
129
+ end
130
+ end
131
+ output_buffer.should have_tag("form label", /Hello task name!/)
132
+ end
133
+
134
+ it 'should be able to translated nested objects with top level translations' do
135
+ semantic_form_for(:order, :url => 'http://test.host') do |builder|
136
+ builder.semantic_fields_for(:line_item) do |f|
137
+ concat(f.input(:name))
138
+ end
139
+ end
140
+ output_buffer.should have_tag("form label", /Hello line item name!/)
141
+ end
142
+
143
+
127
144
  # TODO: Add spec for namespaced models?
128
145
 
129
146
  end
data/spec/input_spec.rb CHANGED
@@ -528,34 +528,35 @@ describe 'SemanticFormBuilder#input' do
528
528
  :formtastic => {
529
529
  :hints => {
530
530
  :title => @default_localized_hint_text,
531
- :post => {
532
- :title => @localized_hint_text
533
- }
534
531
  }
535
532
  }
536
533
  ::Formtastic::SemanticFormBuilder.i18n_lookups_by_default = false
537
534
  end
538
535
 
536
+ after do
537
+ ::I18n.backend.reload!
538
+ end
539
+
539
540
  describe 'when provided value (hint value) is set to TRUE' do
540
541
  it 'should render a hint paragraph containing a localized hint (I18n)' do
541
- semantic_form_for(@new_post) do |builder|
542
- concat(builder.input(:title, :hint => true))
543
- end
544
- output_buffer.should have_tag('form li p.inline-hints', @localized_hint_text)
545
- end
546
-
547
- it 'should render a hint paragraph containing an optional localized hint (I18n) if first is not set' do
548
542
  ::I18n.backend.store_translations :en,
549
543
  :formtastic => {
550
544
  :hints => {
551
545
  :post => {
552
- :title => nil
546
+ :title => @localized_hint_text
553
547
  }
554
548
  }
555
549
  }
556
550
  semantic_form_for(@new_post) do |builder|
557
551
  concat(builder.input(:title, :hint => true))
558
552
  end
553
+ output_buffer.should have_tag('form li p.inline-hints', @localized_hint_text)
554
+ end
555
+
556
+ it 'should render a hint paragraph containing an optional localized hint (I18n) if first is not set' do
557
+ semantic_form_for(@new_post) do |builder|
558
+ concat(builder.input(:title, :hint => true))
559
+ end
559
560
  output_buffer.should have_tag('form li p.inline-hints', @default_localized_hint_text)
560
561
  end
561
562
  end
@@ -177,6 +177,61 @@ describe 'check_boxes input' do
177
177
  end
178
178
 
179
179
 
180
+ describe 'when :disabled is set' do
181
+ before do
182
+ @output_buffer = ''
183
+ end
184
+
185
+ describe "no disabled items" do
186
+ before do
187
+ @new_post.stub!(:author_ids).and_return(nil)
188
+
189
+ semantic_form_for(@new_post) do |builder|
190
+ concat(builder.input(:authors, :as => :check_boxes, :disabled => nil))
191
+ end
192
+ end
193
+
194
+ it 'should not have any disabled item(s)' do
195
+ output_buffer.should_not have_tag("form li fieldset ol li label input[@disabled='disabled']")
196
+ end
197
+ end
198
+
199
+ describe "single disabled item" do
200
+ before do
201
+ @new_post.stub!(:author_ids).and_return(nil)
202
+
203
+ semantic_form_for(@new_post) do |builder|
204
+ concat(builder.input(:authors, :as => :check_boxes, :disabled => @fred.id))
205
+ end
206
+ end
207
+
208
+ it "should have one item disabled; the specified one" do
209
+ output_buffer.should have_tag("form li fieldset ol li label input[@disabled='disabled']", :count => 1)
210
+ output_buffer.should have_tag("form li fieldset ol li label[@for='post_author_ids_#{@fred.id}']", /fred/i)
211
+ output_buffer.should have_tag("form li fieldset ol li label input[@disabled='disabled'][@value='#{@fred.id}']")
212
+ end
213
+ end
214
+
215
+ describe "multiple disabled items" do
216
+ before do
217
+ @new_post.stub!(:author_ids).and_return(nil)
218
+
219
+ semantic_form_for(@new_post) do |builder|
220
+ concat(builder.input(:authors, :as => :check_boxes, :disabled => [@bob.id, @fred.id]))
221
+ end
222
+ end
223
+
224
+ it "should have multiple items disabled; the specified ones" do
225
+ output_buffer.should have_tag("form li fieldset ol li label input[@disabled='disabled']", :count => 2)
226
+ output_buffer.should have_tag("form li fieldset ol li label[@for='post_author_ids_#{@bob.id}']", /bob/i)
227
+ output_buffer.should have_tag("form li fieldset ol li label input[@disabled='disabled'][@value='#{@bob.id}']")
228
+ output_buffer.should have_tag("form li fieldset ol li label[@for='post_author_ids_#{@fred.id}']", /fred/i)
229
+ output_buffer.should have_tag("form li fieldset ol li label input[@disabled='disabled'][@value='#{@fred.id}']")
230
+ end
231
+ end
232
+
233
+ end
234
+
180
235
  end
181
236
 
182
237
 
@@ -26,7 +26,7 @@ describe 'country input' do
26
26
 
27
27
  before do
28
28
  semantic_form_for(@new_post) do |builder|
29
- builder.stub!(:country_select).and_return("<select><option>...</option></select>")
29
+ builder.stub!(:country_select).and_return(Formtastic::Util.html_safe("<select><option>...</option></select>"))
30
30
  concat(builder.input(:country, :as => :country))
31
31
  end
32
32
  end
@@ -54,8 +54,8 @@ describe 'country input' do
54
54
  it "should be passed down to the country_select helper when provided" do
55
55
  priority_countries = ["Foo", "Bah"]
56
56
  semantic_form_for(@new_post) do |builder|
57
- builder.stub!(:country_select).and_return("<select><option>...</option></select>")
58
- builder.should_receive(:country_select).with(:country, priority_countries, {}, {}).and_return("<select><option>...</option></select>")
57
+ builder.stub!(:country_select).and_return(Formtastic::Util.html_safe("<select><option>...</option></select>"))
58
+ builder.should_receive(:country_select).with(:country, priority_countries, {}, {}).and_return(Formtastic::Util.html_safe("<select><option>...</option></select>"))
59
59
 
60
60
  concat(builder.input(:country, :as => :country, :priority_countries => priority_countries))
61
61
  end
@@ -68,13 +68,47 @@ describe 'country input' do
68
68
 
69
69
  semantic_form_for(@new_post) do |builder|
70
70
  builder.stub!(:country_select).and_return("<select><option>...</option></select>")
71
- builder.should_receive(:country_select).with(:country, priority_countries, {}, {}).and_return("<select><option>...</option></select>")
71
+ builder.should_receive(:country_select).with(:country, priority_countries, {}, {}).and_return(Formtastic::Util.html_safe("<select><option>...</option></select>"))
72
72
 
73
73
  concat(builder.input(:country, :as => :country))
74
74
  end
75
75
  end
76
76
 
77
77
  end
78
-
78
+
79
+ describe "matching" do
80
+
81
+ describe "when the attribute is 'country'" do
82
+
83
+ before do
84
+ semantic_form_for(@new_post) do |builder|
85
+ builder.stub!(:country_select).and_return(Formtastic::Util.html_safe("<select><option>...</option></select>"))
86
+ concat(builder.input(:country))
87
+ end
88
+ end
89
+
90
+ it "should render a country input" do
91
+ output_buffer.should have_tag "form li.country"
92
+ end
93
+ end
94
+
95
+ describe "whent the attribute is 'country_something'" do
96
+
97
+ before do
98
+ semantic_form_for(@new_post) do |builder|
99
+ concat(builder.input(:country_subdivision))
100
+ concat(builder.input(:country_code))
101
+ end
102
+ end
103
+
104
+ it "should render a country input" do
105
+ output_buffer.should_not have_tag "form li.country"
106
+ output_buffer.should have_tag "form li.string", :count => 2
107
+ end
108
+
109
+ end
110
+
111
+ end
112
+
79
113
  end
80
114
 
@@ -68,7 +68,7 @@ describe 'date input' do
68
68
  end
69
69
  end
70
70
 
71
- describe 'when the object has no value' do
71
+ describe 'when the object has no value (nil)' do
72
72
  it "should select the :selected if provided as a Date" do
73
73
  output_buffer.replace ''
74
74
  @new_post.stub!(:created_at => nil)
@@ -104,14 +104,13 @@ describe 'date input' do
104
104
  output_buffer.should_not have_tag("form li ol li select#post_created_at_1i option[@selected]")
105
105
  end
106
106
 
107
- it "should select Time.now if a :selected is not provided" do
107
+ it "should select nothing if a :selected is not provided" do
108
108
  output_buffer.replace ''
109
109
  @new_post.stub!(:created_at => nil)
110
110
  semantic_form_for(@new_post) do |builder|
111
111
  concat(builder.input(:created_at, :as => :date))
112
112
  end
113
- output_buffer.should have_tag("form li ol li select#post_created_at_1i option[@selected]", :count => 1)
114
- output_buffer.should have_tag("form li ol li select#post_created_at_1i option[@value='#{Time.now.year}'][@selected]", :count => 1)
113
+ output_buffer.should_not have_tag("form li ol li select option[@selected]")
115
114
 
116
115
  end
117
116
  end
@@ -163,6 +163,21 @@ describe 'datetime input' do
163
163
  end
164
164
  end
165
165
 
166
+ #describe 'when an object is given and the attribute value is nil' do
167
+ # before(:each) do
168
+ # @new_post.stub!(:publish_at).and_return(nil)
169
+ # output_buffer.replace ''
170
+ # semantic_form_for(@new_post) do |builder|
171
+ # concat(builder.input(:publish_at, :as => :datetime))
172
+ # end
173
+ # end
174
+ #
175
+ # it 'should not select a value' do
176
+ # output_buffer.should_not have_tag('form li.datetime option[@selected]')
177
+ # end
178
+ #
179
+ #end
180
+
166
181
  describe ':selected option' do
167
182
 
168
183
  describe "when the object has a value" do
@@ -215,15 +230,13 @@ describe 'datetime input' do
215
230
  output_buffer.should_not have_tag("form li ol li select#post_created_at_1i option[@selected]")
216
231
  end
217
232
 
218
- it "should select Time.now if a :selected is not provided" do
233
+ it "should select nothing if a :selected is not provided" do
219
234
  output_buffer.replace ''
220
235
  @new_post.stub!(:created_at => nil)
221
236
  semantic_form_for(@new_post) do |builder|
222
237
  concat(builder.input(:created_at, :as => :datetime))
223
238
  end
224
- output_buffer.should have_tag("form li ol li select#post_created_at_1i option[@selected]", :count => 1)
225
- output_buffer.should have_tag("form li ol li select#post_created_at_1i option[@value='#{Time.now.year}'][@selected]", :count => 1)
226
-
239
+ output_buffer.should_not have_tag("form li ol li select option[@selected]")
227
240
  end
228
241
  end
229
242
 
@@ -94,6 +94,7 @@ describe 'select input' do
94
94
  before do
95
95
  semantic_form_for(@new_post) do |builder|
96
96
  concat(builder.input(:author, :as => :select))
97
+ concat(builder.input(:reviewer, :as => :select))
97
98
  end
98
99
  end
99
100
 
@@ -108,11 +109,13 @@ describe 'select input' do
108
109
  it 'should have a select inside the wrapper' do
109
110
  output_buffer.should have_tag('form li select')
110
111
  output_buffer.should have_tag('form li select#post_author_id')
112
+ output_buffer.should have_tag('form li select#post_reviewer_id')
111
113
  end
112
114
 
113
115
  it 'should have a valid name' do
114
116
  output_buffer.should have_tag("form li select[@name='post[author_id]']")
115
117
  output_buffer.should_not have_tag("form li select[@name='post[author_id][]']")
118
+ output_buffer.should_not have_tag("form li select[@name='post[reviewer_id][]']")
116
119
  end
117
120
 
118
121
  it 'should not create a multi-select' do
@@ -128,14 +131,14 @@ describe 'select input' do
128
131
  end
129
132
 
130
133
  it 'should have a select option for each Author' do
131
- output_buffer.should have_tag('form li select option', :count => ::Author.find(:all).size + 1)
134
+ output_buffer.should have_tag("form li select[@name='post[author_id]'] option", :count => ::Author.find(:all).size + 1)
132
135
  ::Author.find(:all).each do |author|
133
136
  output_buffer.should have_tag("form li select option[@value='#{author.id}']", /#{author.to_label}/)
134
137
  end
135
138
  end
136
139
 
137
140
  it 'should have one option with a "selected" attribute' do
138
- output_buffer.should have_tag('form li select option[@selected]', :count => 1)
141
+ output_buffer.should have_tag("form li select[@name='post[author_id]'] option[@selected]", :count => 1)
139
142
  end
140
143
 
141
144
  it 'should not singularize the association name' do
@@ -149,20 +152,6 @@ describe 'select input' do
149
152
 
150
153
  output_buffer.should have_tag('form li select#post_author_status_id')
151
154
  end
152
-
153
- it 'should use the "class_name" option' do
154
- @new_post.stub!(:status).and_return(@bob)
155
- @new_post.stub!(:author_status_id).and_return(@bob.id)
156
-
157
- ::Post.stub!(:reflect_on_association).with(:status).and_return(
158
- mock('reflection', :options => {:class_name => 'AuthorStatus'}, :klass => ::Author, :macro => :belongs_to))
159
-
160
- semantic_form_for(@new_post) do |builder|
161
- concat(builder.input(:status, :as => :select))
162
- end
163
-
164
- output_buffer.should have_tag('form li select#post_author_status_id')
165
- end
166
155
  end
167
156
 
168
157
  describe "for a belongs_to association with :group_by => :author" do
@@ -176,6 +165,34 @@ describe 'select input' do
176
165
  end
177
166
  end
178
167
 
168
+ describe "for a belongs_to association with :conditions" do
169
+ before do
170
+ ::Post.stub!(:reflect_on_association).with(:author).and_return do
171
+ mock = mock('reflection', :options => {:conditions => {:active => true}}, :klass => ::Author, :macro => :belongs_to)
172
+ mock.stub!(:[]).with(:class_name).and_return("Author")
173
+ mock
174
+ end
175
+ end
176
+
177
+ it "should call author.find with association conditions" do
178
+ ::Author.should_receive(:merge_conditions).with({:active => true}, nil).and_return(:active => true)
179
+ ::Author.should_receive(:find).with(:all, :conditions => {:active => true})
180
+
181
+ semantic_form_for(@new_post) do |builder|
182
+ concat(builder.input(:author, :as => :select))
183
+ end
184
+ end
185
+
186
+ it "should call author.find with association conditions and find_options conditions" do
187
+ ::Author.should_receive(:merge_conditions).with({:active => true}, {:publisher => true}).and_return(:active => true, :publisher => true)
188
+ ::Author.should_receive(:find).with(:all, :conditions => {:active => true, :publisher => true})
189
+
190
+ semantic_form_for(@new_post) do |builder|
191
+ concat(builder.input(:author, :as => :select, :find_options => {:conditions => {:publisher => true}}))
192
+ end
193
+ end
194
+ end
195
+
179
196
  describe 'for a belongs_to association with :group_by => :continent' do
180
197
  before do
181
198
  @authors = [@bob, @fred, @fred, @fred]
@@ -12,6 +12,7 @@ describe 'time input' do
12
12
 
13
13
  describe "general" do
14
14
  before do
15
+ ::I18n.backend.reload!
15
16
  output_buffer.replace ''
16
17
  end
17
18
 
@@ -94,7 +95,7 @@ describe 'time input' do
94
95
  end
95
96
  end
96
97
 
97
- describe 'when the object has no value' do
98
+ describe 'when the object has no value (nil)' do
98
99
  it "should select the :selected if provided as a Time" do
99
100
  output_buffer.replace ''
100
101
  @new_post.stub!(:created_at => nil)
@@ -118,14 +119,13 @@ describe 'time input' do
118
119
  output_buffer.should_not have_tag("form li ol li select#post_created_at_4i option[@selected]")
119
120
  end
120
121
 
121
- it "should select Time.now if a :selected is not provided" do
122
+ it "should select nothing if a :selected is not provided" do
122
123
  output_buffer.replace ''
123
124
  @new_post.stub!(:created_at => nil)
124
125
  semantic_form_for(@new_post) do |builder|
125
126
  concat(builder.input(:created_at, :as => :time))
126
127
  end
127
- output_buffer.should have_tag("form li ol li select#post_created_at_4i option[@selected]", :count => 1)
128
- output_buffer.should have_tag("form li ol li select#post_created_at_4i option[@value='#{Time.now.hour.to_s.rjust(2,'0')}'][@selected]", :count => 1)
128
+ output_buffer.should_not have_tag("form li ol li select option[@selected]")
129
129
  end
130
130
  end
131
131
 
data/spec/inputs_spec.rb CHANGED
@@ -391,5 +391,4 @@ describe 'SemanticFormBuilder#inputs' do
391
391
  end
392
392
 
393
393
  end
394
-
395
394
  end
data/spec/spec_helper.rb CHANGED
@@ -1,8 +1,8 @@
1
1
  # coding: utf-8
2
2
  require 'rubygems'
3
3
 
4
- gem 'activesupport', '2.3.5'
5
- gem 'actionpack', '2.3.5'
4
+ gem 'activesupport', '2.3.7'
5
+ gem 'actionpack', '2.3.7'
6
6
  require 'active_support'
7
7
  require 'action_pack'
8
8
  require 'action_view'
@@ -22,6 +22,7 @@ Spec::Runner.configure do |config|
22
22
  end
23
23
 
24
24
  require File.expand_path(File.join(File.dirname(__FILE__), '../lib/formtastic'))
25
+ require File.expand_path(File.join(File.dirname(__FILE__), '../lib/formtastic/util'))
25
26
  require File.expand_path(File.join(File.dirname(__FILE__), '../lib/formtastic/layout_helper'))
26
27
 
27
28
 
@@ -126,6 +127,7 @@ module FormtasticSpecHelper
126
127
  @new_post.stub!(:new_record?).and_return(true)
127
128
  @new_post.stub!(:errors).and_return(mock('errors', :[] => nil))
128
129
  @new_post.stub!(:author).and_return(nil)
130
+ @new_post.stub!(:reviewer).and_return(nil)
129
131
  @new_post.stub!(:main_post).and_return(nil)
130
132
  @new_post.stub!(:sub_posts).and_return([]) #TODO should be a mock with methods for adding sub posts
131
133
 
@@ -146,11 +148,16 @@ module FormtasticSpecHelper
146
148
  ::Post.stub!(:human_name).and_return('Post')
147
149
  ::Post.stub!(:reflect_on_all_validations).and_return([])
148
150
  ::Post.stub!(:reflect_on_validations_for).and_return([])
151
+ ::Post.stub!(:reflections).and_return({})
149
152
  ::Post.stub!(:reflect_on_association).and_return do |column_name|
150
153
  case column_name
151
154
  when :author, :author_status
152
155
  mock = mock('reflection', :options => {}, :klass => ::Author, :macro => :belongs_to)
153
156
  mock.stub!(:[]).with(:class_name).and_return("Author")
157
+ mock
158
+ when :reviewer
159
+ mock = mock('reflection', :options => {:class_name => 'Author'}, :klass => ::Author, :macro => :belongs_to)
160
+ mock.stub!(:[]).with(:class_name).and_return("Author")
154
161
  mock
155
162
  when :authors
156
163
  mock('reflection', :options => {}, :klass => ::Author, :macro => :has_and_belongs_to_many)
@@ -173,6 +180,9 @@ module FormtasticSpecHelper
173
180
  @new_post.stub!(:time_zone)
174
181
  @new_post.stub!(:category_name)
175
182
  @new_post.stub!(:allow_comments)
183
+ @new_post.stub!(:country)
184
+ @new_post.stub!(:country_subdivision)
185
+ @new_post.stub!(:country_code)
176
186
  @new_post.stub!(:column_for_attribute).with(:meta_description).and_return(mock('column', :type => :string, :limit => 255))
177
187
  @new_post.stub!(:column_for_attribute).with(:title).and_return(mock('column', :type => :string, :limit => 50))
178
188
  @new_post.stub!(:column_for_attribute).with(:body).and_return(mock('column', :type => :text))
@@ -180,10 +190,17 @@ module FormtasticSpecHelper
180
190
  @new_post.stub!(:column_for_attribute).with(:publish_at).and_return(mock('column', :type => :date))
181
191
  @new_post.stub!(:column_for_attribute).with(:time_zone).and_return(mock('column', :type => :string))
182
192
  @new_post.stub!(:column_for_attribute).with(:allow_comments).and_return(mock('column', :type => :boolean))
193
+ @new_post.stub!(:column_for_attribute).with(:author).and_return(mock('column', :type => :integer))
194
+ @new_post.stub!(:column_for_attribute).with(:country).and_return(mock('column', :type => :string, :limit => 255))
195
+ @new_post.stub!(:column_for_attribute).with(:country_subdivision).and_return(mock('column', :type => :string, :limit => 255))
196
+ @new_post.stub!(:column_for_attribute).with(:country_code).and_return(mock('column', :type => :string, :limit => 255))
183
197
 
184
198
  @new_post.stub!(:author).and_return(@bob)
185
199
  @new_post.stub!(:author_id).and_return(@bob.id)
186
200
 
201
+ @new_post.stub!(:reviewer).and_return(@fred)
202
+ @new_post.stub!(:reviewer_id).and_return(@fred.id)
203
+
187
204
  @new_post.should_receive(:publish_at=).any_number_of_times
188
205
  @new_post.should_receive(:title=).any_number_of_times
189
206
  @new_post.stub!(:main_post_id).and_return(nil)
metadata CHANGED
@@ -5,8 +5,8 @@ version: !ruby/object:Gem::Version
5
5
  segments:
6
6
  - 0
7
7
  - 9
8
- - 8
9
- version: 0.9.8
8
+ - 9
9
+ version: 0.9.9
10
10
  platform: ruby
11
11
  authors:
12
12
  - Justin French
@@ -14,7 +14,7 @@ autorequire:
14
14
  bindir: bin
15
15
  cert_chain: []
16
16
 
17
- date: 2010-03-31 00:00:00 +11:00
17
+ date: 2010-05-25 00:00:00 +10:00
18
18
  default_executable:
19
19
  dependencies:
20
20
  - !ruby/object:Gem::Dependency
@@ -97,6 +97,7 @@ files:
97
97
  - lib/formtastic.rb
98
98
  - lib/formtastic/i18n.rb
99
99
  - lib/formtastic/layout_helper.rb
100
+ - lib/formtastic/util.rb
100
101
  - lib/locale/en.yml
101
102
  - rails/init.rb
102
103
  - spec/buttons_spec.rb