active_scaffold 3.3.0.rc3 → 3.3.0

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