active_scaffold 3.3.0 → 3.3.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (62) hide show
  1. data/CHANGELOG +18 -0
  2. data/app/assets/javascripts/active_scaffold.js.erb +8 -0
  3. data/app/assets/javascripts/jquery/active_scaffold.js +11 -7
  4. data/app/assets/javascripts/jquery/date_picker_bridge.js.erb +19 -0
  5. data/app/assets/javascripts/prototype/active_scaffold.js +2 -0
  6. data/app/assets/stylesheets/active_scaffold_layout.css +5 -1
  7. data/app/views/active_scaffold_overrides/_field_search.html.erb +2 -2
  8. data/app/views/active_scaffold_overrides/_form_association.html.erb +5 -5
  9. data/app/views/active_scaffold_overrides/_form_association_record.html.erb +21 -16
  10. data/app/views/active_scaffold_overrides/_horizontal_subform.html.erb +8 -8
  11. data/app/views/active_scaffold_overrides/_horizontal_subform_header.html.erb +1 -1
  12. data/app/views/active_scaffold_overrides/_list.html.erb +1 -1
  13. data/app/views/active_scaffold_overrides/_list_calculations.html.erb +5 -7
  14. data/app/views/active_scaffold_overrides/_list_inline_adapter.html.erb +1 -12
  15. data/app/views/active_scaffold_overrides/_list_pagination.html.erb +1 -1
  16. data/app/views/active_scaffold_overrides/_list_record.html.erb +2 -2
  17. data/app/views/active_scaffold_overrides/_list_with_header.html.erb +1 -1
  18. data/app/views/active_scaffold_overrides/_render_field.js.erb +1 -1
  19. data/app/views/active_scaffold_overrides/_update_calculations.js.erb +1 -0
  20. data/app/views/active_scaffold_overrides/_vertical_subform.html.erb +2 -4
  21. data/app/views/active_scaffold_overrides/destroy.js.erb +1 -1
  22. data/app/views/active_scaffold_overrides/edit_associated.js.erb +2 -2
  23. data/config/locales/de.yml +109 -109
  24. data/config/locales/en.yml +109 -111
  25. data/config/locales/es.yml +112 -113
  26. data/config/locales/fr.yml +119 -125
  27. data/config/locales/hu.yml +109 -110
  28. data/config/locales/ja.yml +109 -110
  29. data/config/locales/ru.yml +119 -121
  30. data/lib/active_scaffold.rb +2 -2
  31. data/lib/active_scaffold/actions/common_search.rb +7 -3
  32. data/lib/active_scaffold/actions/core.rb +1 -0
  33. data/lib/active_scaffold/actions/field_search.rb +2 -1
  34. data/lib/active_scaffold/actions/list.rb +7 -1
  35. data/lib/active_scaffold/actions/subform.rb +2 -4
  36. data/lib/active_scaffold/attribute_params.rb +2 -4
  37. data/lib/active_scaffold/bridges/calendar_date_select.rb +1 -1
  38. data/lib/active_scaffold/bridges/date_picker.rb +4 -1
  39. data/lib/active_scaffold/bridges/date_picker/helper.rb +6 -6
  40. data/lib/active_scaffold/bridges/file_column.rb +1 -1
  41. data/lib/active_scaffold/bridges/file_column/as_file_column_bridge.rb +1 -1
  42. data/lib/active_scaffold/bridges/file_column/file_column_helpers.rb +1 -1
  43. data/lib/active_scaffold/bridges/paperclip.rb +1 -1
  44. data/lib/active_scaffold/bridges/paperclip/paperclip_bridge_helpers.rb +1 -1
  45. data/lib/active_scaffold/bridges/shared/date_bridge.rb +1 -1
  46. data/lib/active_scaffold/config/base.rb +6 -1
  47. data/lib/active_scaffold/config/core.rb +16 -0
  48. data/lib/active_scaffold/config/list.rb +4 -0
  49. data/lib/active_scaffold/data_structures/column.rb +10 -3
  50. data/lib/active_scaffold/extensions/action_view_rendering.rb +10 -5
  51. data/lib/active_scaffold/helpers/association_helpers.rb +20 -5
  52. data/lib/active_scaffold/helpers/form_column_helpers.rb +31 -21
  53. data/lib/active_scaffold/helpers/list_column_helpers.rb +8 -5
  54. data/lib/active_scaffold/helpers/pagination_helpers.rb +8 -0
  55. data/lib/active_scaffold/helpers/search_column_helpers.rb +20 -6
  56. data/lib/active_scaffold/helpers/view_helpers.rb +6 -6
  57. data/lib/active_scaffold/version.rb +1 -1
  58. data/test/bridges/paperclip_test.rb +2 -2
  59. data/vendor/assets/javascripts/getprototypeof.js +12 -0
  60. data/vendor/assets/javascripts/jquery-ui-timepicker-addon.js +1 -1
  61. metadata +5 -5
  62. data/app/views/active_scaffold_overrides/_search_attribute.html.erb +0 -10
@@ -16,7 +16,6 @@ require 'active_scaffold/engine' unless defined? ACTIVE_SCAFFOLD_PLUGIN
16
16
  require 'json' # for js_config
17
17
 
18
18
  module ActiveScaffold
19
- METHOD_CONVERSION = RUBY_VERSION < '1.9' ? :to_s : :to_sym
20
19
  autoload :AttributeParams, 'active_scaffold/attribute_params'
21
20
  autoload :Configurable, 'active_scaffold/configurable'
22
21
  autoload :Constraints, 'active_scaffold/constraints'
@@ -108,7 +107,8 @@ module ActiveScaffold
108
107
  active_scaffold_config.actions.each do |action_name|
109
108
  conf_instance = active_scaffold_config.send(action_name) rescue next
110
109
  next if conf_instance.class::UserSettings == ActiveScaffold::Config::Base::UserSettings # if it hasn't been extended, skip it
111
- conf_instance.user = conf_instance.class::UserSettings.new(conf_instance, active_scaffold_session_storage, params)
110
+ storage = active_scaffold_config.store_user_settings ? active_scaffold_session_storage : {}
111
+ conf_instance.user = conf_instance.class::UserSettings.new(conf_instance, storage, params)
112
112
  end
113
113
  end
114
114
  end
@@ -2,11 +2,15 @@ module ActiveScaffold::Actions
2
2
  module CommonSearch
3
3
  protected
4
4
  def store_search_params_into_session
5
- active_scaffold_session_storage[:search] = params.delete :search if params[:search]
5
+ if active_scaffold_config.store_user_settings
6
+ active_scaffold_session_storage[:search] = params.delete :search if params[:search]
7
+ else
8
+ @search_params = params.delete :search
9
+ end
6
10
  end
7
-
11
+
8
12
  def search_params
9
- active_scaffold_session_storage[:search]
13
+ @search_params || active_scaffold_session_storage[:search]
10
14
  end
11
15
 
12
16
  def search_ignore?
@@ -7,6 +7,7 @@ module ActiveScaffold::Actions
7
7
  after_filter :clear_storage
8
8
  rescue_from ActiveScaffold::RecordNotAllowed, ActiveScaffold::ActionNotAllowed, :with => :deny_access
9
9
  end
10
+ base.helper_method :successful?
10
11
  base.helper_method :nested?
11
12
  base.helper_method :calculate_query
12
13
  base.helper_method :new_model
@@ -6,6 +6,7 @@ module ActiveScaffold::Actions
6
6
  base.before_filter :store_search_params_into_session, :only => [:index]
7
7
  base.before_filter :do_search, :only => [:index]
8
8
  base.helper_method :field_search_params
9
+ base.helper_method :search_params
9
10
  end
10
11
 
11
12
  # FieldSearch uses params[:search] and not @record because search conditions do not always pass the Model's validations.
@@ -51,7 +52,7 @@ module ActiveScaffold::Actions
51
52
  column = active_scaffold_config.columns[key]
52
53
  search_condition = self.class.condition_for_column(column, value, text_search)
53
54
  unless search_condition.blank?
54
- self.active_scaffold_outer_joins << column.search_joins unless column.includes.present? && list_columns.include?(column)
55
+ self.active_scaffold_outer_joins << column.search_joins unless active_scaffold_config.list.user.count_includes.nil? && column.includes.present? && list_columns.include?(column)
55
56
  self.active_scaffold_conditions << search_condition
56
57
  filtered_columns << column
57
58
  end
@@ -61,7 +61,12 @@ module ActiveScaffold::Actions
61
61
  # The actual algorithm to prepare for the list view
62
62
  def set_includes_for_columns(action = :list)
63
63
  @cache_associations = true
64
- includes_for_list_columns = active_scaffold_config.send(action).columns.collect_visible(:flatten => true){ |c| c.includes }.flatten.uniq.compact
64
+ columns = if respond_to?(:"#{action}_columns")
65
+ send(:"#{action}_columns")
66
+ else
67
+ active_scaffold_config.send(action).columns.collect_visible(:flatten => true)
68
+ end
69
+ includes_for_list_columns = columns.map{ |c| c.includes }.flatten.uniq.compact
65
70
  self.active_scaffold_includes.concat includes_for_list_columns
66
71
  end
67
72
 
@@ -114,6 +119,7 @@ module ActiveScaffold::Actions
114
119
 
115
120
  def each_record_in_scope
116
121
  do_search if respond_to? :do_search, true
122
+ set_includes_for_columns
117
123
  append_to_query(beginning_of_chain, finder_options).all.each {|record| yield record}
118
124
  end
119
125
 
@@ -2,7 +2,7 @@ module ActiveScaffold::Actions
2
2
  module Subform
3
3
  def edit_associated
4
4
  do_edit_associated
5
- render :action => 'edit_associated', :formats => [:js]
5
+ render :action => 'edit_associated', :formats => [:js], :readonly => @column.association.options[:readonly]
6
6
  end
7
7
 
8
8
  protected
@@ -15,9 +15,7 @@ module ActiveScaffold::Actions
15
15
  # NOTE: we don't check whether the user is allowed to update this record, because if not, we'll still let them associate the record. we'll just refuse to do more than associate, is all.
16
16
  @record = @column.association.klass.find(params[:associated_id]) if params[:associated_id]
17
17
  @record ||= build_associated(@column, @parent_record)
18
-
19
- @scope = "#{params[:scope]}[#{@column.name}]"
20
- @scope += "[#{@record.id || generate_temporary_id(@record)}]" if @column.plural_association?
18
+ @scope = params[:scope]
21
19
  end
22
20
 
23
21
  end
@@ -57,9 +57,7 @@ module ActiveScaffold
57
57
  parent_record.send(:assign_multiparameter_attributes, multi_parameter_attributes[column.name])
58
58
  elsif attributes.has_key? column.name
59
59
  value = column_value_from_param_value(parent_record, column, attributes[column.name])
60
-
61
- # we avoid assigning a value that already exists because otherwise has_one associations will break (AR bug in has_one_association.rb#replace)
62
- parent_record.send("#{column.name}=", value) unless parent_record.send(column.name) == value
60
+ parent_record.send("#{column.name}=", value)
63
61
  end
64
62
  end
65
63
 
@@ -93,7 +91,7 @@ module ActiveScaffold
93
91
  def column_value_from_param_value(parent_record, column, value)
94
92
  # convert the value, possibly by instantiating associated objects
95
93
  form_ui = column.form_ui || column.column.try(:type)
96
- if form_ui && self.respond_to?("column_value_for_#{form_ui}_type")
94
+ if form_ui && self.respond_to?("column_value_for_#{form_ui}_type", true)
97
95
  self.send("column_value_for_#{form_ui}_type", parent_record, column, value)
98
96
  elsif value.is_a?(Hash)
99
97
  column_value_from_param_hash_value(parent_record, column, value)
@@ -3,7 +3,7 @@ class ActiveScaffold::Bridges::CalendarDateSelect < ActiveScaffold::DataStructur
3
3
  # check to see if the old bridge was installed. If so, warn them
4
4
  # we can detect this by checking to see if the bridge was installed before calling this code
5
5
 
6
- if ActiveScaffold::Config::Core.instance_methods.include?("initialize_with_calendar_date_select".send(::ActiveScaffold::METHOD_CONVERSION))
6
+ if ActiveScaffold::Config::Core.method_defined?(:initialize_with_calendar_date_select)
7
7
  raise RuntimeError, "We've detected that you have active_scaffold_calendar_date_select_bridge installed. This plugin has been moved to core. Please remove active_scaffold_calendar_date_select_bridge to prevent any conflicts"
8
8
  end
9
9
 
@@ -5,7 +5,10 @@ module ActiveScaffold::Bridges
5
5
  require File.join(File.dirname(__FILE__), "date_picker/ext.rb")
6
6
  end
7
7
  def self.install?
8
- ActiveScaffold.js_framework == :jquery
8
+ ActiveScaffold.js_framework == :jquery && jquery_ui_included?
9
+ end
10
+ def self.jquery_ui_included?
11
+ Jquery::Rails.const_defined?('JQUERY_UI_VERSION') || Jquery.const_defined?('Ui')
9
12
  end
10
13
  def self.localization
11
14
  "jQuery(function($){
@@ -131,18 +131,18 @@ module ActiveScaffold::Bridges
131
131
  def to_datepicker_format(rails_format)
132
132
  ActiveScaffold::Bridges::DatePicker::Helper.to_datepicker_format(rails_format)
133
133
  end
134
-
134
+
135
135
  def datepicker_format_options(column, format, options)
136
136
  if column.form_ui == :date_picker
137
137
  js_format = to_datepicker_format(I18n.translate!("date.formats.#{format}"))
138
- options['date:dateFormat'] = js_format unless js_format.nil?
138
+ options['data-dateFormat'] = js_format unless js_format.nil?
139
139
  else
140
140
  rails_time_format = I18n.translate!("time.formats.#{format}")
141
141
  date_format, time_format = datepicker_split_datetime_format(self.to_datepicker_format(rails_time_format))
142
- options['date:dateFormat'] = date_format unless date_format.nil?
142
+ options['data-dateFormat'] = date_format unless date_format.nil?
143
143
  unless time_format.nil?
144
- options['time:timeFormat'] = time_format
145
- options['time:ampm'] = true if rails_time_format.include?('%I')
144
+ options['data-timeFormat'] = time_format
145
+ options['data-ampm'] = true if rails_time_format.include?('%I')
146
146
  end
147
147
  end unless format == :default
148
148
  end
@@ -161,7 +161,7 @@ module ActiveScaffold::Bridges
161
161
  options[:style] = (options[:show].nil? || options[:show]) ? nil : "display: none"
162
162
  format = options.delete(:format) || (column.search_ui == :date_picker ? :default : :picker)
163
163
  datepicker_format_options(column, format, options)
164
- text_field_tag("#{options[:name]}[#{name}]", value ? l(value, :format => format) : nil, options.merge(:id => "#{options[:id]}_#{name}", :name => "#{options[:name]}[#{name}]"))
164
+ text_field_tag("#{options[:name]}[#{name}]", value ? l(value, :format => format) : nil, options.merge(:id => "#{options[:id]}_#{name}", :name => "#{options[:name]}[#{name}]", :object => nil))
165
165
  end
166
166
  end
167
167
 
@@ -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".send(::ActiveScaffold::METHOD_CONVERSION))
3
+ if ActiveScaffold::Config::Core.method_defined?(:initialize_with_file_column)
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")
@@ -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".send(::ActiveScaffold::METHOD_CONVERSION))
27
+ alias_method_chain :initialize, :file_column unless self.method_defined?(:initialize_without_file_column)
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
@@ -9,7 +9,7 @@ module ActiveScaffold
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=".send(::ActiveScaffold::METHOD_CONVERSION))
12
+ klass.send :class_eval, <<-EOF, __FILE__, __LINE__ + 1 unless klass.method_defined?(:"#{field}_with_delete=")
13
13
  attr_reader :delete_#{field}
14
14
 
15
15
  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".send(::ActiveScaffold::METHOD_CONVERSION))
3
+ if ActiveScaffold::Config::Core.method_defined?(:initialize_with_paperclip)
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")
@@ -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}=".send(::ActiveScaffold::METHOD_CONVERSION))
9
+ klass.class_eval <<-EOF, __FILE__, __LINE__ + 1 unless klass.method_defined?(:"delete_#{field}=")
10
10
  attr_reader :delete_#{field}
11
11
 
12
12
  def delete_#{field}=(value)
@@ -57,7 +57,7 @@ module ActiveScaffold
57
57
  def active_scaffold_search_date_bridge_range_tag(column, options, current_search)
58
58
  range_controls = select_tag("search[#{column.name}][range]",
59
59
  options_for_select( ActiveScaffold::Finder::DateRanges.collect{|range| [as_(range.downcase.to_sym), range]}, current_search["range"]),
60
- :class => 'text-input')
60
+ :class => 'text-input', :id => nil)
61
61
  content_tag("span", range_controls.html_safe, :id => "#{options[:id]}_range", :style => (current_search['opt'] == 'RANGE') ? nil : "display: none")
62
62
  end
63
63
 
@@ -58,7 +58,12 @@ module ActiveScaffold::Config
58
58
 
59
59
  def []=(key, value)
60
60
  @session[@action] ||= {}
61
- @session[@action][key] = value
61
+ if value
62
+ @session[@action][key] = value
63
+ else
64
+ @session[@action].delete key
65
+ @session.delete @action if @session[@action].empty?
66
+ end
62
67
  end
63
68
  end
64
69
 
@@ -29,6 +29,14 @@ module ActiveScaffold::Config
29
29
  cattr_accessor :cache_action_link_urls
30
30
  @@cache_action_link_urls = true
31
31
 
32
+ # enable caching of association options
33
+ cattr_accessor :cache_association_options
34
+ @@cache_association_options = true
35
+
36
+ # enable saving user settings in session (per_page, limit, page, sort, search params)
37
+ cattr_accessor :store_user_settings
38
+ @@store_user_settings = true
39
+
32
40
  # lets you disable the DHTML history
33
41
  def self.dhtml_history=(val)
34
42
  @@dhtml_history = val
@@ -98,6 +106,12 @@ module ActiveScaffold::Config
98
106
  # enable caching of action link urls
99
107
  attr_accessor :cache_action_link_urls
100
108
 
109
+ # enable caching of association options
110
+ attr_accessor :cache_association_options
111
+
112
+ # enable saving user settings in session (per_page, limit, page, sort, search params)
113
+ attr_accessor :store_user_settings
114
+
101
115
  # lets you specify whether add a create link for each sti child for a specific controller
102
116
  attr_accessor :sti_create_links
103
117
  def add_sti_create_links?
@@ -147,6 +161,8 @@ module ActiveScaffold::Config
147
161
  @frontend = self.class.frontend
148
162
  @theme = self.class.theme
149
163
  @cache_action_link_urls = self.class.cache_action_link_urls
164
+ @cache_association_options = self.class.cache_association_options
165
+ @store_user_settings = self.class.store_user_settings
150
166
  @sti_create_links = self.class.sti_create_links
151
167
 
152
168
  # inherit from the global set of action links
@@ -235,6 +235,10 @@ module ActiveScaffold::Config
235
235
  nested_default_sorting.nil? ? @conf.sorting : nested_default_sorting
236
236
  end
237
237
 
238
+ def user_sorting?
239
+ @params['sort'] && @params['sort_direction'] != 'reset'
240
+ end
241
+
238
242
  def sorting
239
243
  if @sorting.nil?
240
244
  # we want to store as little as possible in the session, but we want to return a Sorting data structure. so we recreate it each page load based on session data.
@@ -108,12 +108,19 @@ module ActiveScaffold::DataStructures
108
108
  # supported options:
109
109
  # * for association columns
110
110
  # * :select - displays a simple <select> or a collection of checkboxes to (dis)associate records
111
- attr_writer :form_ui
111
+ def form_ui=(value)
112
+ self.list_method = nil if @list_ui.nil? && value != @form_ui
113
+ @form_ui = value
114
+ end
112
115
  def form_ui
113
116
  @form_ui
114
117
  end
115
118
 
116
- attr_writer :list_ui
119
+ def list_ui=(value)
120
+ self.list_method = nil if value != @list_ui
121
+ @list_ui = value
122
+ end
123
+
117
124
  def list_ui
118
125
  @list_ui || @form_ui
119
126
  end
@@ -226,7 +233,7 @@ module ActiveScaffold::DataStructures
226
233
  attr_writer :show_blank_record
227
234
  def show_blank_record?(associated)
228
235
  if @show_blank_record
229
- return false unless self.association.klass.authorized_for?(:crud_type => :create)
236
+ return false unless self.association.klass.authorized_for?(:crud_type => :create) and not self.association.options[:readonly]
230
237
  self.plural_association? or (self.singular_association? and associated.blank?)
231
238
  end
232
239
  end
@@ -66,7 +66,7 @@ module ActionView::Helpers #:nodoc:
66
66
  id = "as_#{eid}-embedded"
67
67
  url_options = {:controller => remote_controller.to_s, :action => 'index'}.merge(options[:params])
68
68
 
69
- if controller.respond_to?(:render_component_into_view)
69
+ if controller.respond_to?(:render_component_into_view, true)
70
70
  controller.send(:render_component_into_view, url_options)
71
71
  else
72
72
  content_tag(:div, :id => id, :class => 'active-scaffold-component') do
@@ -93,7 +93,10 @@ module ActionView::Helpers #:nodoc:
93
93
 
94
94
  options = args[1] || {}
95
95
  options[:locals] ||= {}
96
- options[:locals] = view_stack.last[:locals].merge!(options[:locals]) if view_stack.last && view_stack.last[:locals]
96
+ if view_stack.last
97
+ options[:locals] = view_stack.last[:locals].merge!(options[:locals]) if view_stack.last[:locals]
98
+ options[:object] ||= view_stack.last[:object] if view_stack.last[:object]
99
+ end
97
100
  options[:template] = template
98
101
  # if prefix is active_scaffold_overrides we must try to render with this prefix in following paths
99
102
  if prefix != 'active_scaffold_overrides'
@@ -109,10 +112,12 @@ module ActionView::Helpers #:nodoc:
109
112
  else
110
113
  @_view_paths ||= lookup_context.view_paths.clone
111
114
  last_template = lookup_context.last_template
112
- if args.first.is_a?(Hash)
113
- current_view = {:locals => args.first[:locals]}
114
- view_stack << current_view
115
+ if args[0].is_a?(Hash)
116
+ current_view = {:locals => args[0][:locals], :object => args[0][:object]}
117
+ else # call is render 'partial', locals_hash
118
+ current_view = {:locals => args[1]}
115
119
  end
120
+ view_stack << current_view if current_view
116
121
  lookup_context.view_paths = @_view_paths # reset view_paths in case a view render :super, and then render :partial
117
122
  result = render_without_active_scaffold(*args, &block)
118
123
  view_stack.pop if current_view.present?
@@ -1,6 +1,17 @@
1
1
  module ActiveScaffold
2
2
  module Helpers
3
3
  module AssociationHelpers
4
+ # Cache the optins for select
5
+ def cache_association_options(association, conditions, klass, cache = true)
6
+ if active_scaffold_config.cache_association_options && cache
7
+ @_associations_cache ||= Hash.new { |h,k| h[k] = {} }
8
+ key = [association.name, association.active_record.name, klass.name].join('/')
9
+ @_associations_cache[key][conditions] ||= yield
10
+ else
11
+ yield
12
+ end
13
+ end
14
+
4
15
  # Provides a way to honor the :conditions on an association while searching the association's klass
5
16
  def association_options_find(association, conditions = nil, klass = nil)
6
17
  if klass.nil? && association.options[:polymorphic]
@@ -10,18 +21,22 @@ module ActiveScaffold
10
21
  else
11
22
  return []
12
23
  end
24
+ cache = !block_given?
13
25
  else
26
+ cache = !block_given? && klass.nil?
14
27
  klass ||= association.klass
15
28
  end
16
29
 
17
30
  conditions = options_for_association_conditions(association) if conditions.nil?
18
- relation = klass.where(conditions).where(association.options[:conditions])
19
- relation = relation.includes(association.options[:include]) if association.options[:include]
20
- relation = yield(relation) if block_given?
21
- relation.all
31
+ cache_association_options(association, conditions, klass, cache) do
32
+ relation = klass.where(conditions).where(association.options[:conditions])
33
+ relation = relation.includes(association.options[:include]) if association.options[:include]
34
+ relation = yield(relation) if block_given?
35
+ relation.to_a
36
+ end
22
37
  end
23
38
 
24
- # Provides a way to honor the :conditions on an association while searching the association's klass
39
+ # Sorts the options for select
25
40
  def sorted_association_options_find(association, conditions = nil)
26
41
  association_options_find(association, conditions).sort_by(&:to_label)
27
42
  end
@@ -46,7 +46,7 @@ module ActiveScaffold
46
46
  options[:size] ||= ActionView::Helpers::InstanceTag::DEFAULT_FIELD_OPTIONS["size"]
47
47
  end
48
48
  options[:include_blank] = true if column.column.null and [:date, :datetime, :time].include?(column.column.type)
49
- options[:value] = format_number_value((options[:object] || @raecord).send(column.name), column.options) if column.number?
49
+ options[:value] = format_number_value((options[:object] || @record).send(column.name), column.options) if column.number?
50
50
  text_field(:record, column.name, options.merge(column.options))
51
51
  end
52
52
  end
@@ -57,7 +57,9 @@ module ActiveScaffold
57
57
  end
58
58
  end
59
59
 
60
- def active_scaffold_render_subform_column(column, scope, crud_type, readonly, add_class = false)
60
+ def active_scaffold_render_subform_column(column, scope, crud_type, readonly, add_class = false, record = nil)
61
+ Rails.logger.warn "Relying on @record is deprecated, call active_scaffold_render_subform_column with record. Called from #{caller.first.gsub(/(.*:\d+):.*/, '\1')}" if record.nil? # TODO Remove when relying on @record is removed
62
+ record ||= @record # TODO Remove when relying on @record is removed
61
63
  if add_class
62
64
  col_class = []
63
65
  col_class << 'required' if column.required?
@@ -66,12 +68,12 @@ module ActiveScaffold
66
68
  col_class << 'checkbox' if column.form_ui == :checkbox
67
69
  col_class = col_class.join(' ')
68
70
  end
69
- unless readonly and not @record.new_record? or not @record.authorized_for?(:crud_type => crud_type, :column => column.name)
70
- render_column(column, @record, column_renders_as(column), scope, false, col_class)
71
+ unless readonly and not record.new_record? or not record.authorized_for?(:crud_type => crud_type, :column => column.name)
72
+ render_column(column, record, column_renders_as(column), scope, false, col_class)
71
73
  else
72
74
  options = active_scaffold_input_options(column, scope).except(:name)
73
75
  options[:class] = "#{options[:class]} #{col_class}" if col_class
74
- content_tag :span, get_column_value(@record, column), options
76
+ content_tag :span, get_column_value(record, column), options
75
77
  end
76
78
  end
77
79
 
@@ -103,14 +105,17 @@ module ActiveScaffold
103
105
  end
104
106
 
105
107
  def update_columns_options(column, scope, options)
108
+ record = options[:object]
109
+ Rails.logger.warn "Relying on @record is deprecated, call update_columns_options with record. Called from #{caller.first.gsub(/(.*:\d+):.*/, '\1')}" if record.nil? # TODO Remove when relying on @record is removed
110
+ record ||= @record # TODO Remove when relying on @record is removed
106
111
  form_action = if scope
107
- subform_controller = controller.class.active_scaffold_controller_for(@record.class)
112
+ subform_controller = controller.class.active_scaffold_controller_for(record.class)
108
113
  subform_controller.active_scaffold_config.subform
109
114
  elsif [:new, :create, :edit, :update, :render_field].include? params[:action].to_sym
110
- active_scaffold_config.send(@record.new_record? ? :create : :update)
115
+ active_scaffold_config.send(record.new_record? ? :create : :update)
111
116
  end
112
117
  if form_action && column.update_columns && (column.update_columns & form_action.columns.names).present?
113
- url_params = params_for(:action => 'render_field', :column => column.name, :id => @record.id)
118
+ url_params = params_for(:action => 'render_field', :column => column.name, :id => record.id)
114
119
  url_params = url_params.except(:parent_scaffold, :association, nested.param_name) if nested? && scope
115
120
  url_params[:eid] = params[:eid] if params[:eid]
116
121
  if scope
@@ -133,34 +138,38 @@ module ActiveScaffold
133
138
 
134
139
  def render_column(column, record, renders_as, scope = nil, only_value = false, col_class = nil)
135
140
  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 }
141
+ render :partial => override_form_field_partial(column), :locals => { :column => column, :only_value => only_value, :scope => scope, :col_class => col_class, :record => record }
137
142
  elsif renders_as == :field || override_form_field?(column)
138
- form_attribute(column, record, scope, only_value)
143
+ form_attribute(column, record, scope, only_value, col_class)
139
144
  elsif renders_as == :subform
140
- render :partial => 'form_association', :locals => { :column => column, :scope => scope }
145
+ render :partial => 'form_association', :locals => { :column => column, :scope => scope, :parent_record => record }
141
146
  else
142
147
  form_hidden_attribute(column, record, scope)
143
148
  end
144
149
  end
145
150
 
146
151
  def form_attribute(column, record, scope = nil, only_value = false, col_class = nil)
147
- column_options = active_scaffold_input_options(column, scope)
152
+ column_options = active_scaffold_input_options(column, scope, :object => record)
148
153
  attributes = field_attributes(column, record)
149
154
  attributes[:class] = "#{attributes[:class]} #{col_class}" if col_class.present?
150
155
  field = unless only_value
151
- active_scaffold_input_for column, scope, column_options.merge(:object => record)
156
+ active_scaffold_input_for column, scope, column_options
152
157
  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))
158
+ content_tag(:span, get_column_value(record, column), column_options.except(:name, :object)) <<
159
+ hidden_field(:record, column.association ? column.association.foreign_key : column.name, column_options)
155
160
  end
156
161
 
157
162
  content_tag :dl, attributes do
158
- %|<dt>#{label_tag column_options[:id], column.label}</dt><dd>#{field}
163
+ %|<dt>#{label_tag label_for(column, column_options), column.label}</dt><dd>#{field}
159
164
  #{loading_indicator_tag(:action => :render_field, :id => params[:id]) if column.update_columns}
160
165
  #{content_tag :span, column.description, :class => 'description' if column.description.present?}
161
166
  </dd>|.html_safe
162
167
  end
163
168
  end
169
+
170
+ def label_for(column, options)
171
+ options[:id] unless column.form_ui == :select && column.plural_association?
172
+ end
164
173
 
165
174
  def form_hidden_attribute(column, record, scope = nil)
166
175
  %|<dl style="display: none;"><dt></dt><dd>
@@ -219,7 +228,7 @@ module ActiveScaffold
219
228
  end
220
229
 
221
230
  def active_scaffold_checkbox_list(column, select_options, associated_ids, options)
222
- html = hidden_field_tag("#{options[:name]}[]", '')
231
+ html = hidden_field_tag("#{options[:name]}[]", '', :id => nil)
223
232
  html << content_tag(:ul, :class => "#{options[:class]} checkbox-list", :id => options[:id]) do
224
233
  content = ''.html_safe
225
234
  select_options.each_with_index do |option, i|
@@ -403,16 +412,17 @@ module ActiveScaffold
403
412
  end
404
413
  end
405
414
 
406
- def column_scope(column, scope = nil)
415
+ def column_scope(column, scope = nil, record = nil)
416
+ Rails.logger.warn "Relying on @record is deprecated, call column_scope with record. Called from #{caller.first.gsub(/(.*:\d+):.*/, '\1')}" if record.nil? # TODO Remove when relying on @record is removed
407
417
  if column.plural_association?
408
- "#{scope}[#{column.name}][#{@record.id || generate_temporary_id}]"
418
+ "#{scope}[#{column.name}][#{record.id || generate_temporary_id}]"
409
419
  else
410
420
  "#{scope}[#{column.name}]"
411
421
  end
412
422
  end
413
423
 
414
424
  def active_scaffold_add_existing_input(options)
415
- if ActiveScaffold.js_framework == :prototype && controller.respond_to?(:record_select_config)
425
+ if ActiveScaffold.js_framework == :prototype && controller.respond_to?(:record_select_config, true)
416
426
  remote_controller = active_scaffold_controller_for(record_select_config.model).controller_path
417
427
  options.merge!(:controller => remote_controller)
418
428
  options.merge!(active_scaffold_input_text_options)
@@ -426,7 +436,7 @@ module ActiveScaffold
426
436
  end
427
437
 
428
438
  def active_scaffold_add_existing_label
429
- if controller.respond_to?(:record_select_config)
439
+ if controller.respond_to?(:record_select_config, true)
430
440
  record_select_config.model.model_name.human
431
441
  else
432
442
  active_scaffold_config.model.model_name.human