active_scaffold 3.3.0.rc3 → 3.3.0

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.
Files changed (60) hide show
  1. data/CHANGELOG +16 -4
  2. data/README.md +67 -0
  3. data/app/assets/javascripts/jquery/active_scaffold.js +9 -9
  4. data/app/views/active_scaffold_overrides/_form.html.erb +4 -4
  5. data/app/views/active_scaffold_overrides/_form_association.html.erb +3 -2
  6. data/app/views/active_scaffold_overrides/_form_association_footer.html.erb +6 -4
  7. data/app/views/active_scaffold_overrides/_horizontal_subform.html.erb +1 -1
  8. data/app/views/active_scaffold_overrides/_list.html.erb +1 -1
  9. data/app/views/active_scaffold_overrides/_list_messages.html.erb +1 -1
  10. data/app/views/active_scaffold_overrides/_refresh_list.js.erb +4 -0
  11. data/app/views/active_scaffold_overrides/_render_field.js.erb +3 -2
  12. data/app/views/active_scaffold_overrides/_vertical_subform.html.erb +1 -1
  13. data/app/views/active_scaffold_overrides/edit_associated.js.erb +1 -1
  14. data/app/views/active_scaffold_overrides/on_create.js.erb +2 -1
  15. data/app/views/active_scaffold_overrides/render_field_inplace.html.erb +6 -1
  16. data/config/locales/ru.yml +6 -6
  17. data/lib/active_scaffold/actions/core.rb +2 -2
  18. data/lib/active_scaffold/actions/create.rb +1 -0
  19. data/lib/active_scaffold/actions/field_search.rb +4 -5
  20. data/lib/active_scaffold/actions/list.rb +13 -13
  21. data/lib/active_scaffold/actions/mark.rb +1 -1
  22. data/lib/active_scaffold/actions/search.rb +2 -2
  23. data/lib/active_scaffold/actions/show.rb +3 -3
  24. data/lib/active_scaffold/actions/subform.rb +2 -1
  25. data/lib/active_scaffold/actions/update.rb +1 -0
  26. data/lib/active_scaffold/attribute_params.rb +6 -2
  27. data/lib/active_scaffold/bridges/bitfields/bitfields_bridge.rb +4 -1
  28. data/lib/active_scaffold/bridges/calendar_date_select.rb +1 -1
  29. data/lib/active_scaffold/bridges/carrierwave/form_ui.rb +2 -2
  30. data/lib/active_scaffold/bridges/date_picker/helper.rb +1 -1
  31. data/lib/active_scaffold/bridges/dragonfly/form_ui.rb +2 -2
  32. data/lib/active_scaffold/bridges/file_column/as_file_column_bridge.rb +1 -1
  33. data/lib/active_scaffold/bridges/file_column/file_column_helpers.rb +2 -2
  34. data/lib/active_scaffold/bridges/file_column.rb +1 -1
  35. data/lib/active_scaffold/bridges/paperclip/form_ui.rb +2 -2
  36. data/lib/active_scaffold/bridges/paperclip/paperclip_bridge_helpers.rb +1 -1
  37. data/lib/active_scaffold/bridges/paperclip.rb +1 -1
  38. data/lib/active_scaffold/bridges/tiny_mce/helpers.rb +1 -1
  39. data/lib/active_scaffold/config/list.rb +9 -1
  40. data/lib/active_scaffold/constraints.rb +2 -2
  41. data/lib/active_scaffold/data_structures/action_columns.rb +2 -2
  42. data/lib/active_scaffold/data_structures/action_links.rb +3 -3
  43. data/lib/active_scaffold/data_structures/column.rb +16 -1
  44. data/lib/active_scaffold/extensions/action_view_rendering.rb +17 -5
  45. data/lib/active_scaffold/extensions/left_outer_joins.rb +33 -0
  46. data/lib/active_scaffold/extensions/paginator_extensions.rb +8 -0
  47. data/lib/active_scaffold/extensions/unsaved_associated.rb +4 -4
  48. data/lib/active_scaffold/finder.rb +13 -7
  49. data/lib/active_scaffold/helpers/controller_helpers.rb +11 -1
  50. data/lib/active_scaffold/helpers/form_column_helpers.rb +50 -27
  51. data/lib/active_scaffold/helpers/list_column_helpers.rb +9 -3
  52. data/lib/active_scaffold/helpers/view_helpers.rb +8 -8
  53. data/lib/active_scaffold/tableless.rb +8 -0
  54. data/lib/active_scaffold/version.rb +1 -1
  55. data/lib/active_scaffold.rb +1 -0
  56. data/lib/generators/active_scaffold_controller/templates/controller.rb +7 -1
  57. metadata +7 -10
  58. data/README +0 -66
  59. data/app/views/active_scaffold_overrides/_form_attribute.html.erb +0 -27
  60. data/app/views/active_scaffold_overrides/_form_hidden_attribute.html.erb +0 -7
@@ -2,7 +2,7 @@ module ActiveScaffold
2
2
  module Helpers
3
3
  module FormColumnHelpers
4
4
  def active_scaffold_input_carrierwave(column, options)
5
- options = active_scaffold_input_text_options(options)
5
+ options = active_scaffold_input_text_options(options.merge(column.options))
6
6
  carrierwave = @record.send("#{column.name}")
7
7
  if !carrierwave.file.blank?
8
8
 
@@ -42,4 +42,4 @@ module ActiveScaffold
42
42
  end
43
43
  end
44
44
  end
45
- end
45
+ end
@@ -71,7 +71,7 @@ module ActiveScaffold::Bridges
71
71
 
72
72
  def self.datetime_options(locale)
73
73
  begin
74
- rails_time_format = I18n.translate! 'time.formats.picker', :locale => locale
74
+ rails_time_format = I18n.translate! 'time.formats.picker', :locale => locale, :default => '%a, %d %b %Y %H:%M:%S'
75
75
  datetime_picker_options = {:ampm => false,
76
76
  :hourText => I18n.translate!('datetime.prompts.hour', :locale => locale),
77
77
  :minuteText => I18n.translate!('datetime.prompts.minute', :locale => locale),
@@ -2,7 +2,7 @@ module ActiveScaffold
2
2
  module Helpers
3
3
  module FormColumnHelpers
4
4
  def active_scaffold_input_dragonfly(column, options)
5
- options = active_scaffold_input_text_options(options)
5
+ options = active_scaffold_input_text_options(options.merge(column.options))
6
6
  input = file_field(:record, column.name, options)
7
7
  dragonfly = @record.send("#{column.name}")
8
8
  if dragonfly.present?
@@ -24,4 +24,4 @@ module ActiveScaffold
24
24
  end
25
25
  end
26
26
  end
27
- end
27
+ end
@@ -24,7 +24,7 @@ module ActiveScaffold::Config
24
24
  }
25
25
  end
26
26
 
27
- alias_method_chain :initialize, :file_column unless self.instance_methods.include?("initialize_without_file_column")
27
+ alias_method_chain :initialize, :file_column unless self.instance_methods.include?("initialize_without_file_column".send(::ActiveScaffold::METHOD_CONVERSION))
28
28
 
29
29
  def configure_file_column_field(field)
30
30
  # set list_ui first because it gets its default value from form_ui
@@ -4,12 +4,12 @@ module ActiveScaffold
4
4
  module FileColumnHelpers
5
5
  class << self
6
6
  def file_column_fields(klass)
7
- klass.instance_methods.grep(/_just_uploaded\?$/).collect{|m| m[0..-16].to_sym }
7
+ klass.instance_methods.select{|m| m.to_s =~ /_just_uploaded\?$/}.collect{|m| m[0..-16].to_sym }
8
8
  end
9
9
 
10
10
  def generate_delete_helpers(klass)
11
11
  file_column_fields(klass).each { |field|
12
- klass.send :class_eval, <<-EOF, __FILE__, __LINE__ + 1 unless klass.methods.include?("#{field}_with_delete=")
12
+ klass.send :class_eval, <<-EOF, __FILE__, __LINE__ + 1 unless klass.methods.include?("#{field}_with_delete=".send(::ActiveScaffold::METHOD_CONVERSION))
13
13
  attr_reader :delete_#{field}
14
14
 
15
15
  def delete_#{field}=(value)
@@ -1,6 +1,6 @@
1
1
  class ActiveScaffold::Bridges::FileColumn < ActiveScaffold::DataStructures::Bridge
2
2
  def self.install
3
- if ActiveScaffold::Config::Core.instance_methods.include?("initialize_with_file_column")
3
+ if ActiveScaffold::Config::Core.instance_methods.include?("initialize_with_file_column".send(::ActiveScaffold::METHOD_CONVERSION))
4
4
  raise RuntimeError, "We've detected that you have active_scaffold_file_column_bridge installed. This plugin has been moved to core. Please remove active_scaffold_file_column_bridge to prevent any conflicts"
5
5
  end
6
6
  require File.join(File.dirname(__FILE__), "file_column/as_file_column_bridge")
@@ -2,7 +2,7 @@ module ActiveScaffold
2
2
  module Helpers
3
3
  module FormColumnHelpers
4
4
  def active_scaffold_input_paperclip(column, options)
5
- options = active_scaffold_input_text_options(options)
5
+ options = active_scaffold_input_text_options(options.merge(column.options))
6
6
  input = file_field(:record, column.name, options)
7
7
  paperclip = @record.send("#{column.name}")
8
8
  if paperclip.file?
@@ -24,4 +24,4 @@ module ActiveScaffold
24
24
  end
25
25
  end
26
26
  end
27
- end
27
+ end
@@ -6,7 +6,7 @@ module ActiveScaffold
6
6
  self.thumbnail_style = :thumbnail
7
7
 
8
8
  def self.generate_delete_helper(klass, field)
9
- klass.class_eval <<-EOF, __FILE__, __LINE__ + 1 unless klass.instance_methods.include?("delete_#{field}=")
9
+ klass.class_eval <<-EOF, __FILE__, __LINE__ + 1 unless klass.instance_methods.include?("delete_#{field}=".send(::ActiveScaffold::METHOD_CONVERSION))
10
10
  attr_reader :delete_#{field}
11
11
 
12
12
  def delete_#{field}=(value)
@@ -1,6 +1,6 @@
1
1
  class ActiveScaffold::Bridges::Paperclip < ActiveScaffold::DataStructures::Bridge
2
2
  def self.install
3
- if ActiveScaffold::Config::Core.instance_methods.include?("initialize_with_paperclip")
3
+ if ActiveScaffold::Config::Core.instance_methods.include?("initialize_with_paperclip".send(::ActiveScaffold::METHOD_CONVERSION))
4
4
  raise RuntimeError, "We've detected that you have active_scaffold_paperclip_bridge installed. This plugin has been moved to core. Please remove active_scaffold_paperclip_bridge to prevent any conflicts"
5
5
  end
6
6
  require File.join(File.dirname(__FILE__), "paperclip/form_ui")
@@ -16,7 +16,7 @@ class ActiveScaffold::Bridges::TinyMce
16
16
  options[:class] = "#{options[:class]} mceEditor #{column.options[:class]}".strip
17
17
 
18
18
  settings = { :theme => 'simple' }.merge(column.options[:tinymce] || {})
19
- settings = settings.to_s.gsub(/:(.+?)\=\>/, '\1:')
19
+ settings = settings.to_json
20
20
  settings = "tinyMCE.settings = #{settings};"
21
21
 
22
22
  html = []
@@ -25,10 +25,15 @@ module ActiveScaffold::Config
25
25
  @always_show_create = self.class.always_show_create
26
26
  @messages_above_header = self.class.messages_above_header
27
27
  @auto_select_columns = self.class.auto_select_columns
28
+ @refresh_with_header = self.class.refresh_with_header
28
29
  end
29
30
 
30
31
  # global level configuration
31
32
  # --------------------------
33
+ # include list header on refresh
34
+ cattr_accessor :refresh_with_header
35
+ @@refresh_with_header = false
36
+
32
37
  # how many records to show per page
33
38
  cattr_accessor :per_page
34
39
  @@per_page = 15
@@ -96,6 +101,9 @@ module ActiveScaffold::Config
96
101
 
97
102
  public :columns=
98
103
 
104
+ # include list header on refresh
105
+ attr_accessor :refresh_with_header
106
+
99
107
  # how many rows to show at once
100
108
  attr_accessor :per_page
101
109
 
@@ -199,7 +207,7 @@ module ActiveScaffold::Config
199
207
  attr_writer :label
200
208
  # This label has alread been localized.
201
209
  def label
202
- @label || @conf.label
210
+ self[:label] || @label || @conf.label
203
211
  end
204
212
 
205
213
  def per_page
@@ -69,7 +69,7 @@ module ActiveScaffold
69
69
 
70
70
  # regular column constraints
71
71
  elsif column.searchable? && params[column.name] != v
72
- active_scaffold_includes.concat column.includes
72
+ active_scaffold_includes.concat column.includes if column.includes.present?
73
73
  conditions << [column.search_sql.collect { |search_sql| "#{search_sql} = ?" }.join(' OR '), *([v] * column.search_sql.size)]
74
74
  end
75
75
  # unknown-to-activescaffold-but-real-database-column constraint
@@ -79,7 +79,7 @@ module ActiveScaffold
79
79
  raise ActiveScaffold::MalformedConstraint, constraint_error(active_scaffold_config.model, k), caller
80
80
  end
81
81
  end
82
- conditions
82
+ conditions.reject(&:blank?)
83
83
  end
84
84
 
85
85
  # We do NOT want to use .search_sql. If anything, search_sql will refer
@@ -93,7 +93,7 @@ module ActiveScaffold::DataStructures
93
93
  options[:for] ||= @columns.active_record_class
94
94
  self.unauthorized_columns = []
95
95
  @set.each do |item|
96
- unless item.is_a? ActiveScaffold::DataStructures::ActionColumns
96
+ unless item.is_a? ActiveScaffold::DataStructures::ActionColumns || @columns.nil?
97
97
  item = (@columns[item] || ActiveScaffold::DataStructures::Column.new(item.to_sym, @columns.active_record_class))
98
98
  next if self.skip_column?(item, options)
99
99
  end
@@ -111,7 +111,7 @@ module ActiveScaffold::DataStructures
111
111
  # skip if this matches a constrained column
112
112
  result = true if constraint_columns.include?(column.name.to_sym)
113
113
  # skip this field if it's not authorized
114
- unless options[:for].authorized_for?(:action => options[:action], :crud_type => options[:crud_type] || self.action.crud_type, :column => column.name)
114
+ unless options[:for].authorized_for?(:action => options[:action], :crud_type => options[:crud_type] || self.action.try(:crud_type), :column => column.name)
115
115
  self.unauthorized_columns << column.name.to_sym
116
116
  result = true
117
117
  end
@@ -70,8 +70,8 @@ module ActiveScaffold::DataStructures
70
70
 
71
71
  def delete(val)
72
72
  self.each({:include_set => true}) do |link, set|
73
- if link.action == val.to_s
74
- set.delete_if {|item| item.is_a?(ActiveScaffold::DataStructures::ActionLink) && item.action == val.to_s}
73
+ if link.action.to_s == val.to_s
74
+ set.delete link
75
75
  end
76
76
  end
77
77
  end
@@ -79,7 +79,7 @@ module ActiveScaffold::DataStructures
79
79
  def delete_group(name)
80
80
  @set.each do |group|
81
81
  if group.name == name
82
- @set.delete_if {|item| item.is_a?(ActiveScaffold::DataStructures::ActionLinks) && item.name == name}
82
+ @set.delete group
83
83
  else
84
84
  group.delete_group(name)
85
85
  end if group.is_a?(ActiveScaffold::DataStructures::ActionLinks)
@@ -174,6 +174,18 @@ module ActiveScaffold::DataStructures
174
174
  end
175
175
  end
176
176
 
177
+ # a collection of associations to do left join when this column is included on search
178
+ def search_joins
179
+ @search_joins || @includes
180
+ end
181
+
182
+ def search_joins=(value)
183
+ @search_joins = case value
184
+ when Array then value
185
+ else [value] # automatically convert to an array
186
+ end
187
+ end
188
+
177
189
  # a collection of columns to load when eager loading is disabled, if it's nil all columns will be loaded
178
190
  attr_accessor :select_associated_columns
179
191
 
@@ -335,7 +347,10 @@ module ActiveScaffold::DataStructures
335
347
 
336
348
  @weight = estimate_weight
337
349
 
338
- self.includes = (association and not polymorphic_association?) ? [association.name] : []
350
+ if association && !polymorphic_association?
351
+ self.includes = [association.name]
352
+ self.search_joins = self.includes.clone
353
+ end
339
354
  end
340
355
 
341
356
  # just the field (not table.field)
@@ -43,11 +43,23 @@ module ActionView::Helpers #:nodoc:
43
43
  constraints = options[:constraints]
44
44
  conditions = options[:conditions]
45
45
  eid = Digest::MD5.hexdigest(params[:controller] + remote_controller.to_s + constraints.to_s + conditions.to_s)
46
- eid_info = {}
47
- eid_info[:constraints] = constraints if constraints
48
- eid_info[:conditions] = conditions if conditions
49
- eid_info[:list] = {:label => args.first[:label]} if args.first[:label]
50
- session["as:#{eid}"] = eid_info
46
+ eid_info = session["as:#{eid}"] ||= {}
47
+ if constraints
48
+ eid_info[:constraints] = constraints
49
+ else
50
+ eid_info.delete :constraints
51
+ end
52
+ if conditions
53
+ eid_info[:conditions] = conditions
54
+ else
55
+ eid_info.delete :conditions
56
+ end
57
+ if options[:label]
58
+ eid_info[:list] = {:label => options[:label]}
59
+ else
60
+ eid_info.delete :list
61
+ end
62
+ session.delete "as:#{eid}" if eid_info.empty?
51
63
  options[:params] ||= {}
52
64
  options[:params].merge! :eid => eid, :embedded => true
53
65
 
@@ -0,0 +1,33 @@
1
+ module ActiveScaffold
2
+ module OuterJoins
3
+ def outer_joins(*assocs)
4
+ joins(outer_joins_sql(*assocs))
5
+ end
6
+
7
+ private
8
+ def outer_joins_sql(*assocs)
9
+ assocs.collect do |assoc|
10
+ if assoc.is_a? Array
11
+ outer_joins_sql(*assoc)
12
+ elsif assoc.is_a? Hash
13
+ assoc.collect do |key, val|
14
+ [left_outer_join_sql(key), klass.reflect_on_association(key).klass.outer_joins_sql(*val)]
15
+ end
16
+ elsif assoc.is_a? Symbol
17
+ left_outer_join_sql(assoc)
18
+ elsif assoc
19
+ assoc
20
+ end
21
+ end.flatten.compact
22
+ end
23
+
24
+ def left_outer_join_sql(association_name)
25
+ t = ActiveRecord::Associations::JoinDependency.new(klass, association_name, []).join_associations.first.join_relation(klass).arel
26
+ t.joins(t)
27
+ end
28
+ end
29
+ end
30
+ ActiveRecord::Relation.send :include, ActiveScaffold::OuterJoins
31
+ module ActiveRecord::Querying
32
+ delegate :outer_joins, :outer_joins_sql, :to => :scoped
33
+ end
@@ -20,6 +20,14 @@ class Paginator
20
20
  next_without_infinite?
21
21
  end
22
22
  alias_method_chain :next?, :infinite
23
+
24
+ def empty?
25
+ if @pager.infinite?
26
+ items.to_a.empty?
27
+ else
28
+ @pager.count == 0
29
+ end
30
+ end
23
31
  end
24
32
 
25
33
  end
@@ -47,10 +47,10 @@ class ActiveRecord::Base
47
47
  # returns false if any yield returns false.
48
48
  # returns true otherwise, even when none of the associations have been instantiated. build wrapper methods accordingly.
49
49
  def with_unsaved_associated
50
- associations_for_update.all? do |association|
51
- association_proxy = send(association.name)
52
- if association_proxy
53
- records = association_proxy
50
+ associations_for_update.all? do |assoc|
51
+ association_proxy = self.association(assoc.name)
52
+ if association_proxy.target.present?
53
+ records = association_proxy.target
54
54
  records = [records] unless records.is_a? Array # convert singular associations into collections for ease of use
55
55
  records.select {|r| r.unsaved? and not r.readonly?}.all? {|r| yield r} # must use select instead of find_all, which Rails overrides on association proxies for db access
56
56
  else
@@ -292,6 +292,11 @@ module ActiveScaffold
292
292
  @active_scaffold_habtm_joins ||= []
293
293
  end
294
294
 
295
+ attr_writer :active_scaffold_outer_joins
296
+ def active_scaffold_outer_joins
297
+ @active_scaffold_outer_joins ||= []
298
+ end
299
+
295
300
  def all_conditions
296
301
  [
297
302
  active_scaffold_conditions, # from the search modules
@@ -299,7 +304,7 @@ module ActiveScaffold
299
304
  conditions_from_params, # from the parameters (e.g. /users/list?first_name=Fred)
300
305
  conditions_from_constraints, # from any constraints (embedded scaffolds)
301
306
  active_scaffold_session_storage[:conditions] # embedding conditions (weaker constraints)
302
- ]
307
+ ].reject(&:blank?)
303
308
  end
304
309
 
305
310
  # returns a single record (the given id) but only if it's allowed for the specified security options.
@@ -324,6 +329,7 @@ module ActiveScaffold
324
329
  finder_options = { :reorder => options[:sorting].try(:clause),
325
330
  :conditions => search_conditions,
326
331
  :joins => joins_for_finder,
332
+ :outer_joins => active_scaffold_outer_joins,
327
333
  :includes => full_includes,
328
334
  :select => options[:select]}
329
335
 
@@ -332,7 +338,7 @@ module ActiveScaffold
332
338
  end
333
339
 
334
340
  def count_items(find_options = {}, count_includes = nil)
335
- count_includes ||= find_options[:includes] unless find_options[:conditions].nil?
341
+ count_includes ||= find_options[:includes] unless find_options[:conditions].blank?
336
342
  options = find_options.reject{|k,v| [:select, :reorder].include? k}
337
343
  options[:includes] = count_includes
338
344
 
@@ -377,22 +383,22 @@ module ActiveScaffold
377
383
  pager.page(options[:page])
378
384
  end
379
385
 
380
- def calculate(column)
386
+ def calculate_query
381
387
  conditions = all_conditions
382
388
  includes = active_scaffold_config.list.count_includes
383
- includes ||= active_scaffold_includes unless conditions.nil?
389
+ includes ||= active_scaffold_includes unless conditions.blank?
384
390
  primary_key = active_scaffold_config.model.primary_key
385
- subquery = append_to_query(beginning_of_chain, :conditions => conditions, :joins => joins_for_collection)
391
+ subquery = append_to_query(beginning_of_chain, :conditions => conditions, :joins => joins_for_finder, :outer_joins => active_scaffold_outer_joins)
386
392
  subquery = subquery.select(active_scaffold_config.columns[primary_key].field)
387
393
  if includes
388
394
  includes_relation = beginning_of_chain.includes(includes)
389
395
  subquery = subquery.send(:apply_join_dependency, subquery, includes_relation.send(:construct_join_dependency_for_association_find))
390
396
  end
391
- beginning_of_chain.where(primary_key => subquery).calculate(column.calculate, column.name)
397
+ active_scaffold_config.model.where(primary_key => subquery)
392
398
  end
393
399
 
394
400
  def append_to_query(query, options)
395
- options.assert_valid_keys :where, :select, :group, :reorder, :limit, :offset, :joins, :includes, :lock, :readonly, :from, :conditions
401
+ options.assert_valid_keys :where, :select, :group, :reorder, :limit, :offset, :joins, :outer_joins, :includes, :lock, :readonly, :from, :conditions
396
402
  query = apply_conditions(query, *options[:conditions]) if options[:conditions]
397
403
  options.reject{|k, v| k == :conditions || v.blank?}.inject(query) do |query, (k, v)|
398
404
  query.send((k.to_sym), v)
@@ -2,11 +2,21 @@ module ActiveScaffold
2
2
  module Helpers
3
3
  module ControllerHelpers
4
4
  def self.included(controller)
5
- controller.class_eval { helper_method :params_for, :conditions_from_params, :main_path_to_return, :render_parent?, :render_parent_options, :render_parent_action, :nested_singular_association?, :build_associated}
5
+ controller.class_eval { helper_method :params_for, :conditions_from_params, :main_path_to_return, :render_parent?, :render_parent_options, :render_parent_action, :nested_singular_association?, :build_associated, :generate_temporary_id, :generated_id}
6
6
  end
7
7
 
8
8
  include ActiveScaffold::Helpers::IdHelpers
9
9
 
10
+ def generate_temporary_id(record = nil, generated_id = nil)
11
+ (generated_id || (Time.now.to_f*1000).to_i.to_s).tap do |id|
12
+ (@temporary_ids ||= {})[record.class.name] = id if record
13
+ end
14
+ end
15
+
16
+ def generated_id(record)
17
+ @temporary_ids[record.class.name] if record && @temporary_ids
18
+ end
19
+
10
20
  def params_for(options = {})
11
21
  # :adapter and :position are one-use rendering arguments. they should not propagate.
12
22
  # :sort, :sort_direction, and :page are arguments that stored in the session. they need not propagate.
@@ -4,19 +4,17 @@ module ActiveScaffold
4
4
  module FormColumnHelpers
5
5
  # This method decides which input to use for the given column.
6
6
  # It does not do any rendering. It only decides which method is responsible for rendering.
7
- def active_scaffold_input_for(column, scope = nil, options = {})
8
- options = active_scaffold_input_options(column, scope, options)
7
+ def active_scaffold_input_for(column, scope = nil, options = nil)
8
+ options ||= active_scaffold_input_options(column, scope)
9
9
  options = update_columns_options(column, scope, options)
10
10
  active_scaffold_render_input(column, options)
11
11
  end
12
12
 
13
- alias form_column active_scaffold_input_for
14
-
15
13
  def active_scaffold_render_input(column, options)
16
14
  begin
17
15
  # first, check if the dev has created an override for this specific field
18
16
  if (method = override_form_field(column))
19
- send(method, @record, options)
17
+ send(method, options[:object] || @record, options)
20
18
  # second, check if the dev has specified a valid form_ui for this column
21
19
  elsif column.form_ui and (method = override_input(column.form_ui))
22
20
  send(method, column, options)
@@ -31,7 +29,7 @@ module ActiveScaffold
31
29
  raise "Unknown form_ui `#{column.form_ui}' for column `#{column.name}'"
32
30
  end
33
31
  elsif column.virtual?
34
- options[:value] = format_number_value(@record.send(column.name), column.options) if column.number?
32
+ options[:value] = format_number_value((options[:object] || @record).send(column.name), column.options) if column.number?
35
33
  active_scaffold_input_virtual(column, options)
36
34
 
37
35
  else # regular model attribute column
@@ -48,7 +46,7 @@ module ActiveScaffold
48
46
  options[:size] ||= ActionView::Helpers::InstanceTag::DEFAULT_FIELD_OPTIONS["size"]
49
47
  end
50
48
  options[:include_blank] = true if column.column.null and [:date, :datetime, :time].include?(column.column.type)
51
- options[:value] = format_number_value(@record.send(column.name), column.options) if column.number?
49
+ options[:value] = format_number_value((options[:object] || @raecord).send(column.name), column.options) if column.number?
52
50
  text_field(:record, column.name, options.merge(column.options))
53
51
  end
54
52
  end
@@ -69,7 +67,7 @@ module ActiveScaffold
69
67
  col_class = col_class.join(' ')
70
68
  end
71
69
  unless readonly and not @record.new_record? or not @record.authorized_for?(:crud_type => crud_type, :column => column.name)
72
- render :partial => form_partial_for_column(column), :locals => { :column => column, :scope => scope, :col_class => col_class }
70
+ render_column(column, @record, column_renders_as(column), scope, false, col_class)
73
71
  else
74
72
  options = active_scaffold_input_options(column, scope).except(:name)
75
73
  options[:class] = "#{options[:class]} #{col_class}" if col_class
@@ -95,7 +93,7 @@ module ActiveScaffold
95
93
  options[:placeholder] = column.placeholder if column.placeholder.present?
96
94
 
97
95
  # Fix for keeping unique IDs in subform
98
- id_control = "record_#{column.name}_#{[params[:eid], params[:id]].compact.join '_'}"
96
+ id_control = "record_#{column.name}_#{[params[:eid], params[:parent_id] || params[:id]].compact.join '_'}"
99
97
  id_control += scope_id(scope) if scope
100
98
 
101
99
  classes = "#{column.name}-input"
@@ -112,12 +110,13 @@ module ActiveScaffold
112
110
  active_scaffold_config.send(@record.new_record? ? :create : :update)
113
111
  end
114
112
  if form_action && column.update_columns && (column.update_columns & form_action.columns.names).present?
115
- url_params = {:action => 'render_field', :column => column.name, :id => nil}
116
- url_params[:id] = @record.id if column.send_form_on_update_column
113
+ url_params = params_for(:action => 'render_field', :column => column.name, :id => @record.id)
114
+ url_params = url_params.except(:parent_scaffold, :association, nested.param_name) if nested? && scope
117
115
  url_params[:eid] = params[:eid] if params[:eid]
118
116
  if scope
119
117
  url_params[:controller] = subform_controller.controller_path
120
118
  url_params[:scope] = scope
119
+ url_params[:parent_id] = params[:parent_id] || params[:id]
121
120
  end
122
121
 
123
122
  options[:class] = "#{options[:class]} update_form".strip
@@ -131,6 +130,43 @@ module ActiveScaffold
131
130
  def field_attributes(column, record)
132
131
  {}
133
132
  end
133
+
134
+ def render_column(column, record, renders_as, scope = nil, only_value = false, col_class = nil)
135
+ if override_form_field_partial?(column)
136
+ render :partial => override_form_field_partial(column), :locals => { :column => column, :only_value => only_value, :scope => scope, :col_class => col_class }
137
+ elsif renders_as == :field || override_form_field?(column)
138
+ form_attribute(column, record, scope, only_value)
139
+ elsif renders_as == :subform
140
+ render :partial => 'form_association', :locals => { :column => column, :scope => scope }
141
+ else
142
+ form_hidden_attribute(column, record, scope)
143
+ end
144
+ end
145
+
146
+ def form_attribute(column, record, scope = nil, only_value = false, col_class = nil)
147
+ column_options = active_scaffold_input_options(column, scope)
148
+ attributes = field_attributes(column, record)
149
+ attributes[:class] = "#{attributes[:class]} #{col_class}" if col_class.present?
150
+ field = unless only_value
151
+ active_scaffold_input_for column, scope, column_options.merge(:object => record)
152
+ else
153
+ content_tag(:span, get_column_value(@record, column), column_options.except(:name)) <<
154
+ hidden_field(:record, column.association ? column.association.foreign_key : column.name, column_options.merge(:object => record))
155
+ end
156
+
157
+ content_tag :dl, attributes do
158
+ %|<dt>#{label_tag column_options[:id], column.label}</dt><dd>#{field}
159
+ #{loading_indicator_tag(:action => :render_field, :id => params[:id]) if column.update_columns}
160
+ #{content_tag :span, column.description, :class => 'description' if column.description.present?}
161
+ </dd>|.html_safe
162
+ end
163
+ end
164
+
165
+ def form_hidden_attribute(column, record, scope = nil)
166
+ %|<dl style="display: none;"><dt></dt><dd>
167
+ #{hidden_field :record, column.name, active_scaffold_input_options(column, scope).merge(:object => record)}
168
+ </dd></dl>|.html_safe
169
+ end
134
170
 
135
171
  ##
136
172
  ## Form input methods
@@ -156,7 +192,7 @@ module ActiveScaffold
156
192
  select_options.unshift(associated) unless associated.nil? || select_options.include?(associated)
157
193
 
158
194
  method = column.name
159
- options = {:selected => associated.try(:id), :include_blank => as_(:_select_)}
195
+ options = {:selected => associated.try(:id), :include_blank => as_(:_select_), :object => html_options.delete(:object)}
160
196
 
161
197
  html_options.update(column.options[:html_options] || {})
162
198
  options.update(column.options)
@@ -210,7 +246,7 @@ module ActiveScaffold
210
246
  end
211
247
 
212
248
  def active_scaffold_input_enum(column, html_options)
213
- options = { :selected => @record.send(column.name) }
249
+ options = { :selected => @record.send(column.name), :object => html_options.delete(:object) }
214
250
  options_for_select = active_scaffold_enum_options(column).collect do |text, value|
215
251
  active_scaffold_translated_option(column, text, value)
216
252
  end
@@ -342,19 +378,6 @@ module ActiveScaffold
342
378
  end
343
379
  alias_method :override_input?, :override_input
344
380
 
345
- def form_partial_for_column(column, renders_as = nil)
346
- renders_as ||= column_renders_as(column)
347
- if override_form_field_partial?(column)
348
- override_form_field_partial(column)
349
- elsif renders_as == :field or override_form_field?(column)
350
- "form_attribute"
351
- elsif renders_as == :subform
352
- "form_association"
353
- elsif renders_as == :hidden
354
- "form_hidden_attribute"
355
- end
356
- end
357
-
358
381
  def subform_partial_for_column(column)
359
382
  subform_partial = "#{active_scaffold_config_for(column.association.klass).subform.layout}_subform"
360
383
  if override_subform_partial?(column, subform_partial)
@@ -373,7 +396,7 @@ module ActiveScaffold
373
396
  return :subsection
374
397
  elsif column.active_record_class.locking_column.to_s == column.name.to_s or column.form_ui == :hidden
375
398
  return :hidden
376
- elsif column.association.nil? or column.form_ui or !active_scaffold_config_for(column.association.klass).actions.include?(:subform)
399
+ elsif column.association.nil? or column.form_ui or !active_scaffold_config_for(column.association.klass).actions.include?(:subform) or override_form_field?(column)
377
400
  return :field
378
401
  else
379
402
  return :subform
@@ -226,7 +226,9 @@ module ActiveScaffold
226
226
  column = column.clone
227
227
  column.options = column.options.clone
228
228
  column.form_ui = :select if (column.association && column.form_ui.nil?)
229
- content_tag(:div, active_scaffold_input_for(column), :style => "display:none;", :class => inplace_edit_control_css_class).tap do
229
+ options = active_scaffold_input_options(column)
230
+ options[:class] = "#{options[:class]} inplace_field"
231
+ content_tag(:div, active_scaffold_input_for(column, nil, options), :style => "display:none;", :class => inplace_edit_control_css_class).tap do
230
232
  @record = old_record
231
233
  end
232
234
  end
@@ -300,12 +302,16 @@ module ActiveScaffold
300
302
  :remote => true, :method => :get}
301
303
  url_options = params_for(:action => :index, :page => 1,
302
304
  :sort => column.name, :sort_direction => sort_direction)
303
- link_to column.label, url_options, options
305
+ link_to column_heading_label(column), url_options, options
304
306
  else
305
- content_tag(:p, column.label)
307
+ content_tag(:p, column_heading_label(column))
306
308
  end
307
309
  end
308
310
 
311
+ def column_heading_label(column)
312
+ column.label
313
+ end
314
+
309
315
  def render_nested_view(action_links, record)
310
316
  rendered = []
311
317
  action_links.member.each do |link|