active_scaffold 3.2.20 → 3.3.0.rc

Sign up to get free protection for your applications and to get access to all the features.
Files changed (152) hide show
  1. data/CHANGELOG +19 -13
  2. data/README +66 -0
  3. data/app/assets/javascripts/jquery/active_scaffold.js +156 -113
  4. data/app/assets/javascripts/jquery/active_scaffold_chosen.js +11 -0
  5. data/app/assets/javascripts/jquery/date_picker_bridge.js.erb +0 -1
  6. data/app/assets/javascripts/jquery/jquery.editinplace.js +132 -128
  7. data/app/assets/javascripts/prototype/active_scaffold.js +68 -25
  8. data/{frontends/default/views/_horizontal_subform_footer.html.erb → app/assets/javascripts/prototype/active_scaffold_chosen.js} +0 -0
  9. data/app/assets/stylesheets/active_scaffold_colors.css.scss +8 -1
  10. data/app/assets/stylesheets/active_scaffold_layout.css +14 -8
  11. data/{frontends/default/views → app/views/active_scaffold_overrides}/_add_existing_form.html.erb +0 -0
  12. data/{frontends/default/views → app/views/active_scaffold_overrides}/_base_form.html.erb +0 -0
  13. data/{frontends/default/views → app/views/active_scaffold_overrides}/_create_form.html.erb +0 -0
  14. data/{frontends/default/views → app/views/active_scaffold_overrides}/_create_form_on_list.html.erb +0 -0
  15. data/{frontends/default/views → app/views/active_scaffold_overrides}/_field_search.html.erb +0 -0
  16. data/{frontends/default/views → app/views/active_scaffold_overrides}/_form.html.erb +0 -0
  17. data/{frontends/default/views → app/views/active_scaffold_overrides}/_form_association.html.erb +8 -3
  18. data/{frontends/default/views → app/views/active_scaffold_overrides}/_form_association_footer.html.erb +5 -4
  19. data/app/views/active_scaffold_overrides/_form_association_record.html.erb +85 -0
  20. data/app/views/active_scaffold_overrides/_form_attribute.html.erb +23 -0
  21. data/{frontends/default/views → app/views/active_scaffold_overrides}/_form_hidden_attribute.html.erb +0 -0
  22. data/{frontends/default/views → app/views/active_scaffold_overrides}/_form_messages.html.erb +0 -0
  23. data/app/views/active_scaffold_overrides/_horizontal_subform.html.erb +12 -0
  24. data/app/views/active_scaffold_overrides/_horizontal_subform_footer.html.erb +0 -0
  25. data/{frontends/default/views → app/views/active_scaffold_overrides}/_horizontal_subform_header.html.erb +3 -2
  26. data/{frontends/default/views → app/views/active_scaffold_overrides}/_human_conditions.html.erb +0 -0
  27. data/app/views/active_scaffold_overrides/_list.html.erb +35 -0
  28. data/{frontends/default/views → app/views/active_scaffold_overrides}/_list_calculations.html.erb +0 -0
  29. data/{frontends/default/views → app/views/active_scaffold_overrides}/_list_column_headings.html.erb +0 -0
  30. data/app/views/active_scaffold_overrides/_list_header.html.erb +8 -0
  31. data/{frontends/default/views → app/views/active_scaffold_overrides}/_list_inline_adapter.html.erb +0 -0
  32. data/{frontends/default/views → app/views/active_scaffold_overrides}/_list_messages.html.erb +4 -4
  33. data/{frontends/default/views → app/views/active_scaffold_overrides}/_list_pagination.html.erb +0 -0
  34. data/{frontends/default/views → app/views/active_scaffold_overrides}/_list_pagination_links.html.erb +0 -0
  35. data/app/views/active_scaffold_overrides/_list_record.html.erb +30 -0
  36. data/{frontends/default/views → app/views/active_scaffold_overrides}/_list_with_header.html.erb +0 -0
  37. data/{frontends/default/views → app/views/active_scaffold_overrides}/_messages.html.erb +0 -0
  38. data/app/views/active_scaffold_overrides/_refresh_list.js.erb +1 -0
  39. data/{frontends/default/views → app/views/active_scaffold_overrides}/_render_field.js.erb +9 -1
  40. data/{frontends/default/views → app/views/active_scaffold_overrides}/_row.html.erb +0 -0
  41. data/{frontends/default/views → app/views/active_scaffold_overrides}/_search.html.erb +0 -0
  42. data/{frontends/default/views → app/views/active_scaffold_overrides}/_search_attribute.html.erb +0 -0
  43. data/{frontends/default/views → app/views/active_scaffold_overrides}/_show.html.erb +0 -0
  44. data/{frontends/default/views → app/views/active_scaffold_overrides}/_show_columns.html.erb +0 -0
  45. data/app/views/active_scaffold_overrides/_update_actions.html.erb +9 -0
  46. data/{frontends/default/views → app/views/active_scaffold_overrides}/_update_calculations.js.erb +0 -0
  47. data/app/views/active_scaffold_overrides/_update_column.js.erb +16 -0
  48. data/{frontends/default/views → app/views/active_scaffold_overrides}/_update_form.html.erb +0 -0
  49. data/{frontends/default/views → app/views/active_scaffold_overrides}/_update_messages.js.erb +0 -0
  50. data/app/views/active_scaffold_overrides/_vertical_subform.html.erb +8 -0
  51. data/{frontends/default/views → app/views/active_scaffold_overrides}/action_confirmation.html.erb +0 -0
  52. data/{frontends/default/views → app/views/active_scaffold_overrides}/add_existing.js.erb +0 -0
  53. data/{frontends/default/views → app/views/active_scaffold_overrides}/add_existing_form.html.erb +0 -0
  54. data/{frontends/default/views → app/views/active_scaffold_overrides}/create.html.erb +0 -0
  55. data/{frontends/default/views → app/views/active_scaffold_overrides}/delete.html.erb +0 -0
  56. data/{frontends/default/views → app/views/active_scaffold_overrides}/destroy.js.erb +0 -0
  57. data/{frontends/default/views → app/views/active_scaffold_overrides}/edit_associated.js.erb +1 -1
  58. data/{frontends/default/views → app/views/active_scaffold_overrides}/field_search.html.erb +0 -0
  59. data/{frontends/default/views → app/views/active_scaffold_overrides}/form_messages.js.erb +0 -0
  60. data/{frontends/default/views → app/views/active_scaffold_overrides}/list.html.erb +0 -0
  61. data/{frontends/default/views → app/views/active_scaffold_overrides}/on_action_update.js.erb +3 -3
  62. data/{frontends/default/views → app/views/active_scaffold_overrides}/on_create.js.erb +1 -1
  63. data/{frontends/default/views → app/views/active_scaffold_overrides}/on_mark.js.erb +0 -0
  64. data/{frontends/default/views → app/views/active_scaffold_overrides}/on_update.js.erb +4 -4
  65. data/{frontends/default/views → app/views/active_scaffold_overrides}/render_field.js.erb +0 -0
  66. data/{frontends/default/views → app/views/active_scaffold_overrides}/row.js.erb +1 -1
  67. data/{frontends/default/views → app/views/active_scaffold_overrides}/search.html.erb +0 -0
  68. data/{frontends/default/views → app/views/active_scaffold_overrides}/show.html.erb +0 -0
  69. data/{frontends/default/views → app/views/active_scaffold_overrides}/update.html.erb +1 -1
  70. data/app/views/active_scaffold_overrides/update_column.js.erb +26 -0
  71. data/{frontends/default/views → app/views/active_scaffold_overrides}/update_row.js.erb +0 -0
  72. data/config/locales/de.yml +1 -0
  73. data/config/locales/en.yml +1 -0
  74. data/config/locales/es.yml +1 -0
  75. data/config/locales/fr.yml +1 -0
  76. data/config/locales/hu.yml +1 -0
  77. data/config/locales/ja.yml +1 -0
  78. data/config/locales/ru.yml +1 -0
  79. data/lib/active_scaffold.rb +14 -26
  80. data/lib/active_scaffold/actions/core.rb +14 -11
  81. data/lib/active_scaffold/actions/create.rb +3 -3
  82. data/lib/active_scaffold/actions/delete.rb +3 -0
  83. data/lib/active_scaffold/actions/list.rb +9 -6
  84. data/lib/active_scaffold/actions/mark.rb +1 -1
  85. data/lib/active_scaffold/actions/nested.rb +8 -6
  86. data/lib/active_scaffold/actions/show.rb +6 -1
  87. data/lib/active_scaffold/actions/update.rb +39 -19
  88. data/lib/active_scaffold/active_record_permissions.rb +29 -12
  89. data/lib/active_scaffold/attribute_params.rb +14 -7
  90. data/lib/active_scaffold/bridges/calendar_date_select.rb +1 -1
  91. data/lib/active_scaffold/bridges/cancan/cancan_bridge.rb +1 -2
  92. data/lib/active_scaffold/bridges/carrierwave/list_ui.rb +1 -1
  93. data/lib/active_scaffold/bridges/chosen.rb +14 -0
  94. data/lib/active_scaffold/bridges/chosen/helpers.rb +48 -0
  95. data/lib/active_scaffold/bridges/date_picker/helper.rb +7 -6
  96. data/lib/active_scaffold/bridges/dragonfly/form_ui.rb +1 -1
  97. data/lib/active_scaffold/bridges/dragonfly/list_ui.rb +1 -1
  98. data/lib/active_scaffold/bridges/file_column.rb +1 -1
  99. data/lib/active_scaffold/bridges/file_column/as_file_column_bridge.rb +1 -1
  100. data/lib/active_scaffold/bridges/file_column/file_column_helpers.rb +2 -2
  101. data/lib/active_scaffold/bridges/file_column/list_ui.rb +4 -4
  102. data/lib/active_scaffold/bridges/paperclip.rb +1 -1
  103. data/lib/active_scaffold/bridges/paperclip/form_ui.rb +1 -1
  104. data/lib/active_scaffold/bridges/paperclip/list_ui.rb +1 -1
  105. data/lib/active_scaffold/bridges/paperclip/paperclip_bridge_helpers.rb +1 -1
  106. data/lib/active_scaffold/bridges/shared/date_bridge.rb +1 -1
  107. data/lib/active_scaffold/bridges/tiny_mce/helpers.rb +1 -1
  108. data/lib/active_scaffold/config/core.rb +9 -2
  109. data/lib/active_scaffold/config/list.rb +9 -13
  110. data/lib/active_scaffold/config/nested.rb +11 -2
  111. data/lib/active_scaffold/data_structures/action_columns.rb +19 -5
  112. data/lib/active_scaffold/data_structures/action_link.rb +9 -2
  113. data/lib/active_scaffold/data_structures/action_links.rb +5 -36
  114. data/lib/active_scaffold/data_structures/column.rb +21 -21
  115. data/lib/active_scaffold/data_structures/nested_info.rb +31 -44
  116. data/lib/active_scaffold/extensions/action_controller_rescueing.rb +1 -0
  117. data/lib/active_scaffold/extensions/action_view_rendering.rb +30 -36
  118. data/lib/active_scaffold/extensions/reverse_associations.rb +10 -6
  119. data/lib/active_scaffold/extensions/routing_mapper.rb +6 -5
  120. data/lib/active_scaffold/extensions/unsaved_associated.rb +1 -1
  121. data/lib/active_scaffold/finder.rb +18 -10
  122. data/lib/active_scaffold/helpers/association_helpers.rb +21 -2
  123. data/lib/active_scaffold/helpers/controller_helpers.rb +14 -16
  124. data/lib/active_scaffold/helpers/form_column_helpers.rb +161 -21
  125. data/lib/active_scaffold/helpers/id_helpers.rb +7 -7
  126. data/lib/active_scaffold/helpers/list_column_helpers.rb +42 -92
  127. data/lib/active_scaffold/helpers/search_column_helpers.rb +10 -3
  128. data/lib/active_scaffold/helpers/show_column_helpers.rb +4 -9
  129. data/lib/active_scaffold/helpers/view_helpers.rb +278 -78
  130. data/lib/active_scaffold/version.rb +2 -2
  131. data/lib/generators/active_scaffold_controller/templates/controller.rb +1 -1
  132. data/test/bridges/paperclip_test.rb +2 -2
  133. data/vendor/assets/javascripts/jquery-ui-timepicker-addon.js +1882 -1276
  134. metadata +79 -80
  135. data/README.md +0 -67
  136. data/frontends/default/views/_action_group.html.erb +0 -24
  137. data/frontends/default/views/_form_attribute.html.erb +0 -23
  138. data/frontends/default/views/_horizontal_subform.html.erb +0 -22
  139. data/frontends/default/views/_horizontal_subform_record.html.erb +0 -43
  140. data/frontends/default/views/_list.html.erb +0 -18
  141. data/frontends/default/views/_list_actions.html.erb +0 -15
  142. data/frontends/default/views/_list_header.html.erb +0 -10
  143. data/frontends/default/views/_list_record.html.erb +0 -13
  144. data/frontends/default/views/_list_record_columns.html.erb +0 -8
  145. data/frontends/default/views/_refresh_list.js.erb +0 -1
  146. data/frontends/default/views/_update_actions.html.erb +0 -9
  147. data/frontends/default/views/_vertical_subform.html.erb +0 -12
  148. data/frontends/default/views/_vertical_subform_record.html.erb +0 -43
  149. data/frontends/default/views/refresh_list.js.erb +0 -2
  150. data/frontends/default/views/update_column.js.erb +0 -15
  151. data/lib/active_scaffold/extensions/active_record_offset.rb +0 -12
  152. data/lib/active_scaffold/extensions/nil_id_in_url_params.rb +0 -7
@@ -55,25 +55,25 @@ module ActiveScaffold::Actions
55
55
  end
56
56
 
57
57
  def row_respond_to_js
58
- render
58
+ render :action => 'row'
59
59
  end
60
60
 
61
61
  # The actual algorithm to prepare for the list view
62
- def set_includes_for_list_columns
62
+ def set_includes_for_columns(action = :list)
63
63
  @cache_associations = true
64
- includes_for_list_columns = active_scaffold_config.list.columns.collect{ |c| c.includes }.flatten.uniq.compact
64
+ includes_for_list_columns = active_scaffold_config.send(action).columns.collect{ |c| c.includes }.flatten.uniq.compact
65
65
  self.active_scaffold_includes.concat includes_for_list_columns
66
66
  end
67
67
 
68
68
  def get_row
69
- set_includes_for_list_columns
69
+ set_includes_for_columns
70
70
  klass = beginning_of_chain.includes(active_scaffold_includes)
71
71
  @record = find_if_allowed(params[:id], :read, klass)
72
72
  end
73
73
 
74
74
  # The actual algorithm to prepare for the list view
75
75
  def do_list
76
- set_includes_for_list_columns
76
+ set_includes_for_columns
77
77
 
78
78
  options = { :sorting => active_scaffold_config.list.user.sorting,
79
79
  :count_includes => active_scaffold_config.list.user.count_includes }
@@ -96,6 +96,7 @@ module ActiveScaffold::Actions
96
96
  end
97
97
 
98
98
  def do_refresh_list
99
+ params.delete(:id)
99
100
  do_search if respond_to? :do_search
100
101
  do_list
101
102
  end
@@ -135,7 +136,9 @@ module ActiveScaffold::Actions
135
136
  @action_link = active_scaffold_config.action_links[action_name]
136
137
  if params[:id] && params[:id] && params[:id].to_i > 0
137
138
  crud_type ||= (request.post? || request.put?) ? :update : :delete
138
- @record = find_if_allowed(params[:id], crud_type)
139
+ set_includes_for_columns
140
+ klass = beginning_of_chain.includes(active_scaffold_includes)
141
+ @record = find_if_allowed(params[:id], crud_type, klass)
139
142
  unless @record.nil?
140
143
  yield @record
141
144
  else
@@ -29,7 +29,7 @@ module ActiveScaffold::Actions
29
29
  def mark_respond_to_js
30
30
  if params[:id]
31
31
  do_search if respond_to? :do_search
32
- set_includes_for_list_columns
32
+ set_includes_for_columns if active_scaffold_config.actions.include? :list
33
33
  @page = find_page(:pagination => active_scaffold_config.mark.mark_all_mode != :page)
34
34
  render :action => 'on_mark'
35
35
  else
@@ -37,7 +37,7 @@ module ActiveScaffold::Actions
37
37
  else
38
38
  as_(:nested_for_model, :nested_model => active_scaffold_config.list.label, :parent_model => nested_parent_record.to_label)
39
39
  end
40
- if nested.sorted?
40
+ if nested.sorted? && !active_scaffold_config.nested.ignore_order_from_association
41
41
  active_scaffold_config.list.user.nested_default_sorting = {:table_name => active_scaffold_config.model.model_name, :default_sorting => nested.default_sorting}
42
42
  end
43
43
  end
@@ -73,16 +73,18 @@ module ActiveScaffold::Actions
73
73
  end
74
74
 
75
75
  def beginning_of_chain
76
- if nested? && nested.association && !nested.association.belongs_to?
76
+ if nested? && nested.association
77
77
  if nested.association.collection?
78
- nested.parent_scope.send(nested.association.name)
79
- elsif nested.association.options[:through] # has_one :through doesn't need conditions
78
+ nested_parent_record.send(nested.association.name)
79
+ elsif nested.association.options[:through] || nested.child_association.nil? # has_one :through doesn't need conditions, and without child_association is not possible to add them
80
80
  active_scaffold_config.model
81
81
  elsif nested.child_association.belongs_to?
82
- active_scaffold_config.model.where(nested.child_association.foreign_key => nested.parent_scope)
82
+ active_scaffold_config.model.where(nested.child_association.foreign_key => nested_parent_record)
83
+ elsif nested.association.belongs_to?
84
+ active_scaffold_config.model.joins(nested.child_association.name).where(nested.association.active_record.table_name => {nested.association.active_record.primary_key => nested_parent_record}).readonly(false)
83
85
  end
84
86
  elsif nested? && nested.scope
85
- nested.parent_scope.send(nested.scope)
87
+ nested_parent_record.send(nested.scope)
86
88
  else
87
89
  active_scaffold_config.model
88
90
  end
@@ -41,7 +41,9 @@ module ActiveScaffold::Actions
41
41
  # A simple method to retrieve and prepare a record for showing.
42
42
  # May be overridden to customize show routine
43
43
  def do_show
44
- @record = find_if_allowed(params[:id], :read)
44
+ set_includes_for_columns(:show) if active_scaffold_config.actions.include? :list
45
+ klass = beginning_of_chain.includes(active_scaffold_includes)
46
+ @record = find_if_allowed(params[:id], :read, klass)
45
47
  end
46
48
 
47
49
  # The default security delegates to ActiveRecordPermissions.
@@ -49,6 +51,9 @@ module ActiveScaffold::Actions
49
51
  def show_authorized?(record = nil)
50
52
  (record || self).send(:authorized_for?, :crud_type => :read)
51
53
  end
54
+ def show_ignore?(record = nil)
55
+ !self.send(:authorized_for?, :crud_type => :read)
56
+ end
52
57
  private
53
58
  def show_authorized_filter
54
59
  link = active_scaffold_config.show.link || active_scaffold_config.show.class.link
@@ -18,7 +18,7 @@ module ActiveScaffold::Actions
18
18
  # for inline (inlist) editing
19
19
  def update_column
20
20
  do_update_column
21
- @column_span_id = params[:editor_id] || params[:editorId]
21
+ @column_span_id = params.delete(:editor_id) || params.delete(:editorId)
22
22
  end
23
23
 
24
24
  protected
@@ -35,7 +35,7 @@ module ActiveScaffold::Actions
35
35
  def update_respond_to_html
36
36
  if params[:iframe]=='true' # was this an iframe post ?
37
37
  responds_to_parent do
38
- render :action => 'on_update.js', :layout => false
38
+ render :action => 'on_update', :formats => [:js], :layout => false
39
39
  end
40
40
  else # just a regular post
41
41
  if successful?
@@ -48,7 +48,13 @@ module ActiveScaffold::Actions
48
48
  end
49
49
  def update_respond_to_js
50
50
  if successful?
51
- do_refresh_list if update_refresh_list? && !render_parent?
51
+ if !render_parent? && active_scaffold_config.actions.include?(:list)
52
+ if update_refresh_list?
53
+ do_refresh_list
54
+ else
55
+ get_row
56
+ end
57
+ end
52
58
  flash.now[:info] = as_(:updated_model, :model => @record.to_label) if active_scaffold_config.update.persistent
53
59
  end
54
60
  render :action => 'on_update'
@@ -62,6 +68,7 @@ module ActiveScaffold::Actions
62
68
  def update_respond_to_yaml
63
69
  render :text => Hash.from_xml(response_object.to_xml(:only => active_scaffold_config.update.columns.names)).to_yaml, :content_type => Mime::YAML, :status => response_status
64
70
  end
71
+
65
72
  # A simple method to find and prepare a record for editing
66
73
  # May be overridden to customize the record (set default values, etc.)
67
74
  def do_edit
@@ -81,7 +88,7 @@ module ActiveScaffold::Actions
81
88
  active_scaffold_config.model.transaction do
82
89
  @record = update_record_from_params(@record, active_scaffold_config.update.columns, attributes) unless options[:no_record_param_update]
83
90
  before_update_save(@record)
84
- self.successful = [@record.valid?, @record.associated_valid?].all? {|v| v == true} # this syntax avoids a short-circuit
91
+ self.successful = [@record.valid?, @record.associated_valid?].all? # this syntax avoids a short-circuit
85
92
  if successful?
86
93
  @record.save! and @record.save_associated!
87
94
  after_update_save(@record)
@@ -104,23 +111,33 @@ module ActiveScaffold::Actions
104
111
  end
105
112
 
106
113
  def do_update_column
107
- @record = active_scaffold_config.model.find(params[:id])
108
- if @record.authorized_for?(:crud_type => :update, :column => params[:column])
109
- column = active_scaffold_config.columns[params[:column].to_sym]
110
- unless @record.column_for_attribute(params[:column]).nil? || @record.column_for_attribute(params[:column]).null
111
- if @record.column_for_attribute(params[:column]).default == true
112
- params[:value] ||= false
113
- else
114
- params[:value] ||= @record.column_for_attribute(params[:column]).default
115
- end
114
+ # delete from params so update :table won't break urls, also they shouldn't be used in sort links too
115
+ value = params.delete(:value)
116
+ column = params.delete(:column).to_sym
117
+ params.delete(:original_html)
118
+ params.delete(:original_value)
119
+
120
+ @record = find_if_allowed(params[:id], :read)
121
+ if @record.authorized_for?(:crud_type => :update, :column => column)
122
+ @column = active_scaffold_config.columns[column]
123
+ value ||= unless @column.column.nil? || @column.column.null
124
+ @column.column.default == true ? false : @column.column.default
116
125
  end
117
- unless column.nil?
118
- params[:value] = column_value_from_param_value(@record, column, params[:value])
119
- params[:value] = [] if params[:value].nil? && column.form_ui && column.plural_association?
126
+ unless @column.nil?
127
+ value = column_value_from_param_value(@record, @column, value)
128
+ value = [] if value.nil? && @column.form_ui && @column.plural_association?
120
129
  end
121
- @record.send("#{params[:column]}=", params[:value])
130
+ @record.send("#{@column.name}=", value)
122
131
  before_update_save(@record)
123
- @record.save
132
+ self.successful = @record.save
133
+ if self.successful? && active_scaffold_config.actions.include?(:list)
134
+ if @column.inplace_edit_update == :table
135
+ params.delete(:id)
136
+ do_list
137
+ elsif @column.inplace_edit_update
138
+ get_row
139
+ end
140
+ end
124
141
  after_update_save(@record)
125
142
  end
126
143
  end
@@ -139,7 +156,10 @@ module ActiveScaffold::Actions
139
156
  # The default security delegates to ActiveRecordPermissions.
140
157
  # You may override the method to customize.
141
158
  def update_authorized?(record = nil)
142
- (!nested? || !nested.readonly?) && (record || self).send(:authorized_for?, :crud_type => :update)
159
+ (!nested? || !nested.readonly?) && (record || self).authorized_for?(:crud_type => :update)
160
+ end
161
+ def update_ignore?(record = nil)
162
+ !self.authorized_for?(:crud_type => :update)
143
163
  end
144
164
  private
145
165
  def update_authorized_filter
@@ -65,6 +65,10 @@ module ActiveRecordPermissions
65
65
  def self.included(base)
66
66
  base.extend SecurityMethods
67
67
  base.send :include, SecurityMethods
68
+ class << base
69
+ attr_accessor :class_security_methods
70
+ attr_accessor :instance_security_methods
71
+ end
68
72
  end
69
73
 
70
74
  # Because any class-level queries get delegated to the instance level via a new record,
@@ -85,34 +89,47 @@ module ActiveRecordPermissions
85
89
  def authorized_for?(options = {})
86
90
  raise ArgumentError, "unknown crud type #{options[:crud_type]}" if options[:crud_type] and ![:create, :read, :update, :delete].include?(options[:crud_type])
87
91
 
92
+ # collect other possibly-related methods that actually exist
93
+ methods = cached_authorized_for_methods(options)
94
+ return ActiveRecordPermissions.default_permission if methods.empty?
95
+ return send(methods.first) if methods.one?
96
+
97
+ # if any method returns false, then return false
98
+ return false if methods.any? {|m| !send(m)}
99
+ true
100
+ end
101
+
102
+ def cached_authorized_for_methods(options)
103
+ key = "#{options[:crud_type]}##{options[:column]}##{options[:action]}"
104
+ if self.is_a? Class
105
+ self.class_security_methods ||= {}
106
+ self.class_security_methods[key] ||= authorized_for_methods(options)
107
+ else
108
+ self.class.instance_security_methods ||= {}
109
+ self.class.instance_security_methods[key] ||= authorized_for_methods(options)
110
+ end
111
+ end
112
+
113
+ def authorized_for_methods(options)
88
114
  # column_authorized_for_crud_type? has the highest priority over other methods,
89
115
  # you can disable a crud verb and enable that verb for a column
90
116
  # (for example, disable update and enable inplace_edit in a column)
91
117
  method = column_and_crud_type_security_method(options[:column], options[:crud_type])
92
- return send(method) if method and respond_to?(method)
118
+ return [method] if method and respond_to?(method)
93
119
 
94
120
  # authorized_for_action? has higher priority than other methods,
95
121
  # you can disable a crud verb and enable an action with that crud verb
96
122
  # (for example, disable update and enable an action with update as crud type)
97
123
  method = action_security_method(options[:action])
98
- return send(method) if method and respond_to?(method)
124
+ return [method] if method and respond_to?(method)
99
125
 
100
126
  # collect other possibly-related methods that actually exist
101
127
  methods = [
102
128
  column_security_method(options[:column]),
103
129
  crud_type_security_method(options[:crud_type]),
104
130
  ].compact.select {|m| respond_to?(m)}
105
-
106
- # if any method returns false, then return false
107
- return false if methods.any? {|m| !send(m)}
108
-
109
- # if any method actually exists then it must've returned true, so return true
110
- return true unless methods.empty?
111
-
112
- # if no method exists, return the default permission
113
- return ActiveRecordPermissions.default_permission
114
131
  end
115
-
132
+
116
133
  private
117
134
 
118
135
  def column_security_method(column)
@@ -66,7 +66,7 @@ module ActiveScaffold
66
66
  if parent_record.new_record?
67
67
  parent_record.class.reflect_on_all_associations.each do |a|
68
68
  next unless [:has_one, :has_many].include?(a.macro) and not (a.options[:through] || a.options[:finder_sql])
69
- next unless association_proxy = parent_record.send(a.name)
69
+ next unless (association_proxy = parent_record.send(a.name)).present?
70
70
 
71
71
  raise ActiveScaffold::ReverseAssociationRequired, "Association #{a.name} in class #{parent_record.class.name}: In order to support :has_one and :has_many where the parent record is new and the child record(s) validate the presence of the parent, ActiveScaffold requires the reverse association (the belongs_to)." unless a.reverse
72
72
 
@@ -100,11 +100,18 @@ module ActiveScaffold
100
100
 
101
101
  def column_value_from_param_simple_value(parent_record, column, value)
102
102
  if column.singular_association?
103
- # it's a single id
104
- column.association.klass.find(value) if value and not value.empty?
103
+ if value.present?
104
+ if column.polymorphic_association?
105
+ class_name = parent_record.send(column.association.foreign_type)
106
+ class_name.constantize.find(value) if class_name
107
+ else
108
+ # it's a single id
109
+ column.association.klass.find(value)
110
+ end
111
+ end
105
112
  elsif column.plural_association?
106
113
  column_plural_assocation_value_from_value(column, Array(value))
107
- elsif column.number? && [:i18n_number, :currency].include?(column.options[:format])
114
+ elsif column.number? && [:i18n_number, :currency].include?(column.options[:format]) && column.form_ui != :number
108
115
  self.class.i18n_number_to_native_format(value)
109
116
  else
110
117
  # convert empty strings into nil. this works better with 'null => true' columns (and validations),
@@ -118,7 +125,7 @@ module ActiveScaffold
118
125
  def column_plural_assocation_value_from_value(column, value)
119
126
  # it's an array of ids
120
127
  if value and not value.empty?
121
- ids = value.select {|id| id.respond_to?(:empty?) ? !id.empty? : true}
128
+ ids = value.select {|id| id.present?}
122
129
  ids.empty? ? [] : column.association.klass.find(ids)
123
130
  end
124
131
  end
@@ -137,7 +144,7 @@ module ActiveScaffold
137
144
  manage_nested_record_from_params(parent_record, column, value)
138
145
  elsif column.plural_association?
139
146
  # HACK to be able to delete all associated records, hash will include "0" => ""
140
- value.collect {|key, value| manage_nested_record_from_params(parent_record, column, value) unless value == ""}.compact
147
+ value.sort.collect {|key, value| manage_nested_record_from_params(parent_record, column, value) unless value == ""}.compact
141
148
  else
142
149
  value
143
150
  end
@@ -190,7 +197,7 @@ module ActiveScaffold
190
197
  if value.is_a?(Hash)
191
198
  attributes_hash_is_empty?(value, klass)
192
199
  elsif value.is_a?(Array)
193
- value.all?(&:blank?)
200
+ value.any? {|id| id.respond_to?(:empty?) ? !id.empty? : true}
194
201
  else
195
202
  value.respond_to?(:empty?) ? value.empty? : false
196
203
  end
@@ -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.instance_methods.include?("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
 
@@ -11,8 +11,7 @@ module CanCan
11
11
  module Ability
12
12
  def as_action_aliases
13
13
  alias_action :list, :row, :show_search, :render_field, :to => :read
14
- alias_action :update_column, :add_association, :edit_associated,
15
- :edit_associated, :new_existing, :add_existing, :to => :update
14
+ alias_action :update_column, :edit_associated, :new_existing, :add_existing, :to => :update
16
15
  alias_action :delete, :destroy_existing, :to => :destroy
17
16
  end
18
17
  end
@@ -1,7 +1,7 @@
1
1
  module ActiveScaffold
2
2
  module Helpers
3
3
  module ListColumnHelpers
4
- def active_scaffold_column_carrierwave(column, record)
4
+ def active_scaffold_column_carrierwave(record, column)
5
5
  carrierwave = record.send("#{column.name}")
6
6
  return nil unless !carrierwave.file.blank?
7
7
  thumbnail_style = ActiveScaffold::Bridges::Carrierwave::CarrierwaveBridgeHelpers.thumbnail_style
@@ -0,0 +1,14 @@
1
+ class ActiveScaffold::Bridges::Chosen < ActiveScaffold::DataStructures::Bridge
2
+ def self.install
3
+ require File.join(File.dirname(__FILE__), "chosen/helpers.rb")
4
+ end
5
+ def self.install?
6
+ super && [:jquery, :prototype].include?(ActiveScaffold.js_framework)
7
+ end
8
+ def self.stylesheets
9
+ 'chosen'
10
+ end
11
+ def self.javascripts
12
+ ["chosen-#{ActiveScaffold.js_framework}", "#{ActiveScaffold.js_framework}/active_scaffold_chosen"]
13
+ end
14
+ end
@@ -0,0 +1,48 @@
1
+ class ActiveScaffold::Bridges::Chosen
2
+ module Helpers
3
+ def self.included(base)
4
+ base.class_eval do
5
+ include FormColumnHelpers
6
+ include SearchColumnHelpers
7
+ end
8
+ end
9
+
10
+ module FormColumnHelpers
11
+ # requires RecordSelect plugin to be installed and configured.
12
+ def active_scaffold_input_chosen(column, html_options)
13
+ html_options[:class] << ' chosen'
14
+ if column.plural_association?
15
+ associated_options, select_options = active_scaffold_plural_association_options(column)
16
+ options = {:selected => associated_options.collect {|a| a[1]}, :include_blank => as_(:_select_)}
17
+
18
+ html_options.update(:multiple => true).update(column.options[:html_options] || {})
19
+ options.update(column.options)
20
+ html_options[:name] = "#{html_options[:name]}[]" if html_options[:multiple] == true && !html_options[:name].to_s.ends_with?("[]")
21
+
22
+ if optgroup = options.delete(:optgroup)
23
+ select(:record, column.name, grouped_options_for_select(column, select_options, optgroup), options, html_options)
24
+ else
25
+ collection_select(:record, column.name, select_options, :id, :to_label, options, html_options)
26
+ end
27
+ else
28
+ active_scaffold_input_select(column, html_options)
29
+ end
30
+ end
31
+ end
32
+
33
+ module SearchColumnHelpers
34
+ def active_scaffold_search_chosen(column, options)
35
+ options[:class] << ' chosen'
36
+ active_scaffold_search_select(column, options)
37
+ end
38
+
39
+ def active_scaffold_search_multi_chosen(column, options)
40
+ options[:class] << ' chosen'
41
+ options[:multiple] = true
42
+ active_scaffold_search_select(column, options)
43
+ end
44
+ end
45
+ end
46
+ end
47
+
48
+ ActionView::Base.class_eval { include ActiveScaffold::Bridges::Chosen::Helpers }