active_scaffold 3.4.43 → 3.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/CHANGELOG +39 -0
- data/{LICENSE → LICENSE.md} +1 -1
- data/README.md +27 -19
- data/app/assets/javascripts/active_scaffold.js.erb +1 -1
- data/app/assets/javascripts/jquery/active_scaffold.js +95 -43
- data/app/assets/javascripts/jquery/tiny_mce_bridge.js +30 -6
- data/app/assets/javascripts/prototype/tiny_mce_bridge.js +11 -1
- data/app/assets/stylesheets/active_scaffold_colors.scss +2 -2
- data/app/assets/stylesheets/active_scaffold_layout.css +36 -28
- data/app/views/active_scaffold_overrides/_base_form.html.erb +2 -3
- data/app/views/active_scaffold_overrides/_field_search.html.erb +8 -7
- data/app/views/active_scaffold_overrides/_form_association.html.erb +9 -9
- data/app/views/active_scaffold_overrides/_form_association_footer.html.erb +6 -6
- data/app/views/active_scaffold_overrides/_form_association_record.html.erb +52 -50
- data/app/views/active_scaffold_overrides/_horizontal_subform.html.erb +1 -1
- data/app/views/active_scaffold_overrides/_horizontal_subform_header.html.erb +1 -1
- data/app/views/active_scaffold_overrides/_human_conditions.html.erb +3 -1
- data/app/views/active_scaffold_overrides/_list_calculations.html.erb +1 -1
- data/app/views/active_scaffold_overrides/_list_column_headings.html.erb +2 -0
- data/app/views/active_scaffold_overrides/_list_messages.html.erb +5 -3
- data/app/views/active_scaffold_overrides/_list_record.html.erb +3 -1
- data/app/views/active_scaffold_overrides/_list_with_header.html.erb +9 -9
- data/app/views/active_scaffold_overrides/_messages.html.erb +1 -1
- data/app/views/active_scaffold_overrides/_refresh_list.js.erb +18 -10
- data/app/views/active_scaffold_overrides/_render_field.js.erb +3 -3
- data/app/views/active_scaffold_overrides/_search.html.erb +7 -6
- data/app/views/active_scaffold_overrides/_show_actions.html.erb +14 -0
- data/app/views/active_scaffold_overrides/_show_association.html.erb +1 -1
- data/app/views/active_scaffold_overrides/_update_actions.html.erb +6 -2
- data/app/views/active_scaffold_overrides/_update_column.js.erb +1 -1
- data/app/views/active_scaffold_overrides/_update_form.html.erb +1 -1
- data/app/views/active_scaffold_overrides/destroy.js.erb +2 -3
- data/app/views/active_scaffold_overrides/edit_associated.js.erb +4 -3
- data/app/views/active_scaffold_overrides/on_action_update.js.erb +5 -3
- data/app/views/active_scaffold_overrides/on_create.js.erb +4 -4
- data/app/views/active_scaffold_overrides/on_update.js.erb +6 -6
- data/app/views/active_scaffold_overrides/show.html.erb +6 -0
- data/app/views/active_scaffold_overrides/update.html.erb +1 -1
- data/app/views/active_scaffold_overrides/update_column.js.erb +1 -1
- data/config/brakeman.ignore +26 -0
- data/config/brakeman.yml +3 -0
- data/config/i18n-tasks.yml +121 -0
- data/config/locales/de.yml +81 -70
- data/config/locales/en.yml +83 -74
- data/config/locales/es.yml +82 -73
- data/config/locales/fr.yml +86 -75
- data/config/locales/hu.yml +81 -70
- data/config/locales/ja.yml +71 -60
- data/config/locales/ru.yml +85 -74
- data/lib/active_scaffold.rb +3 -0
- data/lib/active_scaffold/actions/common_search.rb +11 -7
- data/lib/active_scaffold/actions/core.rb +119 -47
- data/lib/active_scaffold/actions/create.rb +1 -1
- data/lib/active_scaffold/actions/delete.rb +11 -8
- data/lib/active_scaffold/actions/field_search.rb +104 -6
- data/lib/active_scaffold/actions/list.rb +25 -21
- data/lib/active_scaffold/actions/mark.rb +12 -4
- data/lib/active_scaffold/actions/nested.rb +26 -26
- data/lib/active_scaffold/actions/search.rb +2 -2
- data/lib/active_scaffold/actions/show.rb +4 -5
- data/lib/active_scaffold/actions/subform.rb +9 -7
- data/lib/active_scaffold/actions/update.rb +20 -13
- data/lib/active_scaffold/active_record_permissions.rb +24 -5
- data/lib/active_scaffold/attribute_params.rb +68 -49
- data/lib/active_scaffold/bridges.rb +1 -1
- data/lib/active_scaffold/bridges/ancestry/ancestry_bridge.rb +15 -19
- data/lib/active_scaffold/bridges/bitfields.rb +1 -1
- data/lib/active_scaffold/bridges/bitfields/bitfields_bridge.rb +10 -14
- data/lib/active_scaffold/bridges/calendar_date_select.rb +0 -7
- data/lib/active_scaffold/bridges/calendar_date_select/as_cds_bridge.rb +19 -22
- data/lib/active_scaffold/bridges/cancan.rb +4 -3
- data/lib/active_scaffold/bridges/cancan/cancan_bridge.rb +11 -21
- data/lib/active_scaffold/bridges/carrierwave.rb +2 -1
- data/lib/active_scaffold/bridges/carrierwave/carrierwave_bridge.rb +2 -6
- data/lib/active_scaffold/bridges/carrierwave/form_ui.rb +6 -39
- data/lib/active_scaffold/bridges/carrierwave/list_ui.rb +1 -1
- data/lib/active_scaffold/bridges/chosen.rb +4 -1
- data/lib/active_scaffold/bridges/chosen/helpers.rb +3 -2
- data/lib/active_scaffold/bridges/country_select/country_select_bridge_helper.rb +2 -2
- data/lib/active_scaffold/bridges/date_picker.rb +3 -0
- data/lib/active_scaffold/bridges/date_picker/ext.rb +43 -38
- data/lib/active_scaffold/bridges/date_picker/helper.rb +24 -23
- data/lib/active_scaffold/bridges/dragonfly.rb +1 -1
- data/lib/active_scaffold/bridges/dragonfly/dragonfly_bridge.rb +3 -7
- data/lib/active_scaffold/bridges/dragonfly/form_ui.rb +3 -25
- data/lib/active_scaffold/bridges/dragonfly/list_ui.rb +2 -2
- data/lib/active_scaffold/bridges/file_column/as_file_column_bridge.rb +6 -8
- data/lib/active_scaffold/bridges/file_column/file_column_helpers.rb +1 -1
- data/lib/active_scaffold/bridges/file_column/form_ui.rb +0 -2
- data/lib/active_scaffold/bridges/file_column/list_ui.rb +2 -1
- data/lib/active_scaffold/bridges/file_column/test/test_helper.rb +1 -1
- data/lib/active_scaffold/bridges/paper_trail/actions.rb +1 -1
- data/lib/active_scaffold/bridges/paper_trail/helper.rb +1 -2
- data/lib/active_scaffold/bridges/paper_trail/paper_trail_bridge.rb +3 -7
- data/lib/active_scaffold/bridges/paperclip.rb +1 -1
- data/lib/active_scaffold/bridges/paperclip/form_ui.rb +3 -28
- data/lib/active_scaffold/bridges/paperclip/list_ui.rb +1 -1
- data/lib/active_scaffold/bridges/paperclip/paperclip_bridge.rb +3 -7
- data/lib/active_scaffold/bridges/record_select.rb +2 -0
- data/lib/active_scaffold/bridges/record_select/helpers.rb +14 -18
- data/lib/active_scaffold/bridges/semantic_attributes/column.rb +4 -8
- data/lib/active_scaffold/bridges/shared/date_bridge.rb +20 -20
- data/lib/active_scaffold/bridges/tiny_mce/helpers.rb +7 -22
- data/lib/active_scaffold/bridges/usa_state_select/usa_state_select_helper.rb +14 -14
- data/lib/active_scaffold/config/base.rb +9 -6
- data/lib/active_scaffold/config/core.rb +30 -21
- data/lib/active_scaffold/config/create.rb +2 -1
- data/lib/active_scaffold/config/delete.rb +2 -2
- data/lib/active_scaffold/config/field_search.rb +9 -3
- data/lib/active_scaffold/config/form.rb +4 -4
- data/lib/active_scaffold/config/list.rb +27 -23
- data/lib/active_scaffold/config/nested.rb +4 -4
- data/lib/active_scaffold/config/search.rb +6 -6
- data/lib/active_scaffold/config/show.rb +11 -1
- data/lib/active_scaffold/config/subform.rb +1 -1
- data/lib/active_scaffold/config/update.rb +4 -2
- data/lib/active_scaffold/constraints.rb +39 -36
- data/lib/active_scaffold/core.rb +36 -15
- data/lib/active_scaffold/data_structures/action_columns.rb +14 -9
- data/lib/active_scaffold/data_structures/action_link.rb +4 -5
- data/lib/active_scaffold/data_structures/action_links.rb +5 -4
- data/lib/active_scaffold/data_structures/actions.rb +2 -2
- data/lib/active_scaffold/data_structures/association.rb +8 -0
- data/lib/active_scaffold/data_structures/association/abstract.rb +147 -0
- data/lib/active_scaffold/data_structures/association/active_mongoid.rb +42 -0
- data/lib/active_scaffold/data_structures/association/active_record.rb +94 -0
- data/lib/active_scaffold/data_structures/association/mongoid.rb +45 -0
- data/lib/active_scaffold/data_structures/bridge.rb +3 -6
- data/lib/active_scaffold/data_structures/column.rb +100 -82
- data/lib/active_scaffold/data_structures/columns.rb +21 -3
- data/lib/active_scaffold/data_structures/nested_info.rb +22 -37
- data/lib/active_scaffold/data_structures/set.rb +4 -4
- data/lib/active_scaffold/data_structures/sorting.rb +29 -15
- data/lib/active_scaffold/engine.rb +3 -1
- data/lib/active_scaffold/extensions/action_controller_rendering.rb +10 -5
- data/lib/active_scaffold/extensions/action_view_rendering.rb +65 -59
- data/lib/active_scaffold/extensions/left_outer_joins.rb +48 -53
- data/lib/active_scaffold/extensions/localize.rb +3 -4
- data/lib/active_scaffold/extensions/name_option_for_datetime.rb +7 -11
- data/lib/active_scaffold/extensions/paginator_extensions.rb +20 -18
- data/lib/active_scaffold/extensions/routing_mapper.rb +104 -40
- data/lib/active_scaffold/extensions/to_label.rb +1 -1
- data/lib/active_scaffold/extensions/unsaved_associated.rb +4 -13
- data/lib/active_scaffold/extensions/unsaved_record.rb +12 -1
- data/lib/active_scaffold/finder.rb +200 -134
- data/lib/active_scaffold/helpers/action_link_helpers.rb +398 -0
- data/lib/active_scaffold/helpers/association_helpers.rb +12 -30
- data/lib/active_scaffold/helpers/controller_helpers.rb +74 -24
- data/lib/active_scaffold/helpers/form_column_helpers.rb +205 -112
- data/lib/active_scaffold/helpers/human_condition_helpers.rb +21 -11
- data/lib/active_scaffold/helpers/id_helpers.rb +1 -1
- data/lib/active_scaffold/helpers/list_column_helpers.rb +117 -39
- data/lib/active_scaffold/helpers/pagination_helpers.rb +11 -14
- data/lib/active_scaffold/helpers/search_column_helpers.rb +69 -32
- data/lib/active_scaffold/helpers/show_column_helpers.rb +9 -3
- data/lib/active_scaffold/helpers/view_helpers.rb +41 -426
- data/lib/active_scaffold/orm_checks.rb +109 -0
- data/lib/active_scaffold/paginator.rb +1 -1
- data/lib/active_scaffold/responds_to_parent.rb +12 -10
- data/lib/active_scaffold/tableless.rb +81 -43
- data/lib/active_scaffold/version.rb +2 -2
- data/lib/generators/active_scaffold/controller_generator.rb +49 -0
- data/lib/generators/active_scaffold/install_generator.rb +45 -0
- data/lib/generators/active_scaffold/resource_generator.rb +56 -0
- data/lib/generators/{active_scaffold_controller/templates → templates}/controller.rb +0 -0
- data/lib/generators/{active_scaffold_controller/templates → templates}/helper.rb +0 -0
- data/shoulda_macros/macros.rb +3 -3
- data/test/active_scaffold_config_mock.rb +33 -0
- data/test/bridges/bridge_test.rb +9 -9
- data/test/bridges/date_picker_test.rb +3 -1
- data/test/bridges/paper_trail_test.rb +2 -3
- data/test/bridges/paperclip_test.rb +21 -10
- data/test/bridges/tiny_mce_test.rb +20 -21
- data/test/class_with_finder.rb +42 -0
- data/test/company.rb +6 -4
- data/test/config/core_test.rb +1 -1
- data/test/config/create_test.rb +1 -1
- data/test/config/list_test.rb +3 -3
- data/test/config/update_test.rb +3 -3
- data/test/data_structures/action_columns_test.rb +3 -3
- data/test/data_structures/association_column_test.rb +5 -5
- data/test/data_structures/column_test.rb +14 -14
- data/test/data_structures/columns_test.rb +2 -2
- data/test/data_structures/set_test.rb +2 -2
- data/test/data_structures/sorting_test.rb +6 -4
- data/test/extensions/active_record_test.rb +1 -1
- data/test/extensions/routing_mapper_test.rb +64 -13
- data/test/helpers/form_column_helpers_test.rb +6 -6
- data/test/helpers/list_column_helpers_test.rb +9 -5
- data/test/helpers/pagination_helpers_test.rb +1 -0
- data/test/misc/active_record_permissions_test.rb +18 -1
- data/test/misc/attribute_params_test.rb +26 -17
- data/test/misc/calculation_test.rb +8 -31
- data/test/misc/configurable_test.rb +3 -2
- data/test/misc/constraints_test.rb +33 -22
- data/test/misc/convert_numbers_format_test.rb +28 -10
- data/test/misc/finder_test.rb +6 -29
- data/test/misc/parse_datetime_test.rb +160 -0
- data/test/misc/render_test.rb +1 -1
- data/test/misc/tableless_test.rb +24 -0
- data/test/mock_app/app/models/building.rb +2 -1
- data/test/mock_app/config.ru +1 -1
- data/test/mock_app/config/environments/test.rb +1 -1
- data/test/mock_app/config/routes.rb +11 -3
- data/test/model_stub.rb +11 -6
- data/test/run_all.rb +1 -1
- data/test/test_helper.rb +19 -4
- metadata +42 -23
- data/lib/active_scaffold/data_structures/error_message.rb +0 -22
- data/lib/active_scaffold/extensions/reverse_associations.rb +0 -119
- data/lib/generators/active_scaffold/USAGE +0 -29
- data/lib/generators/active_scaffold/active_scaffold_generator.rb +0 -21
- data/lib/generators/active_scaffold_controller/USAGE +0 -19
- data/lib/generators/active_scaffold_controller/active_scaffold_controller_generator.rb +0 -29
- data/test/data_structures/error_message_test.rb +0 -25
@@ -22,8 +22,8 @@ module ActiveScaffold::Actions
|
|
22
22
|
columns = active_scaffold_config.search.columns
|
23
23
|
text_search = active_scaffold_config.search.text_search
|
24
24
|
query = query.split(active_scaffold_config.search.split_terms) if active_scaffold_config.search.split_terms
|
25
|
-
search_conditions = self.class.
|
26
|
-
@filtered =
|
25
|
+
search_conditions = self.class.conditions_for_columns(query, columns, text_search)
|
26
|
+
@filtered = search_conditions.present?
|
27
27
|
active_scaffold_conditions.concat search_conditions if @filtered
|
28
28
|
|
29
29
|
references, outer_joins = columns.partition do |column|
|
@@ -1,7 +1,7 @@
|
|
1
1
|
module ActiveScaffold::Actions
|
2
2
|
module Show
|
3
3
|
def self.included(base)
|
4
|
-
base.
|
4
|
+
base.before_action :show_authorized_filter, :only => :show
|
5
5
|
end
|
6
6
|
|
7
7
|
def show
|
@@ -42,14 +42,13 @@ module ActiveScaffold::Actions
|
|
42
42
|
# May be overridden to customize show routine
|
43
43
|
def do_show
|
44
44
|
set_includes_for_columns(:show) if active_scaffold_config.actions.include? :list
|
45
|
-
|
46
|
-
@record = find_if_allowed(params[:id], :read, klass)
|
45
|
+
get_row
|
47
46
|
end
|
48
47
|
|
49
48
|
# The default security delegates to ActiveRecordPermissions.
|
50
49
|
# You may override the method to customize.
|
51
50
|
def show_authorized?(record = nil)
|
52
|
-
(record || self).
|
51
|
+
(record || self).authorized_for?(crud_type: :read, reason: true)
|
53
52
|
end
|
54
53
|
|
55
54
|
def show_ignore?(record = nil)
|
@@ -60,7 +59,7 @@ module ActiveScaffold::Actions
|
|
60
59
|
|
61
60
|
def show_authorized_filter
|
62
61
|
link = active_scaffold_config.show.link || active_scaffold_config.show.class.link
|
63
|
-
raise ActiveScaffold::ActionNotAllowed unless send(link.security_method)
|
62
|
+
raise ActiveScaffold::ActionNotAllowed unless Array(send(link.security_method))[0]
|
64
63
|
end
|
65
64
|
|
66
65
|
def show_formats
|
@@ -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], :readonly => @column.association.
|
5
|
+
render :action => 'edit_associated', :formats => [:js], :readonly => @column.association.readonly?
|
6
6
|
end
|
7
7
|
|
8
8
|
protected
|
@@ -18,13 +18,15 @@ module ActiveScaffold::Actions
|
|
18
18
|
@column = active_scaffold_config.columns[params[:child_association]]
|
19
19
|
|
20
20
|
# 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.
|
21
|
-
|
22
|
-
|
23
|
-
if (
|
24
|
-
if
|
25
|
-
@record.send(
|
21
|
+
if params[:associated_id]
|
22
|
+
@record = @column.association.klass.find(params[:associated_id])
|
23
|
+
if (reverse = @column.association.reverse_association)
|
24
|
+
if reverse.collection?
|
25
|
+
@record.send(reverse.name) << @parent_record
|
26
|
+
elsif @column.association.belongs_to?
|
27
|
+
@parent_record.send("#{@column.name}=", @record)
|
26
28
|
else
|
27
|
-
@record.send("#{
|
29
|
+
@record.send("#{reverse.name}=", @parent_record)
|
28
30
|
end
|
29
31
|
end
|
30
32
|
else
|
@@ -1,7 +1,7 @@
|
|
1
1
|
module ActiveScaffold::Actions
|
2
2
|
module Update
|
3
3
|
def self.included(base)
|
4
|
-
base.
|
4
|
+
base.before_action :update_authorized_filter, :only => %i[edit update]
|
5
5
|
base.helper_method :update_refresh_list?
|
6
6
|
end
|
7
7
|
|
@@ -135,28 +135,35 @@ module ActiveScaffold::Actions
|
|
135
135
|
def do_update_column
|
136
136
|
# delete from params so update :table won't break urls, also they shouldn't be used in sort links too
|
137
137
|
value = params.delete(:value)
|
138
|
-
column = params.delete(:column)
|
138
|
+
column = params.delete(:column)
|
139
139
|
params.delete(:original_html)
|
140
140
|
params.delete(:original_value)
|
141
141
|
@column = active_scaffold_config.columns[column]
|
142
|
-
@record = find_if_allowed(params[:id], :read)
|
142
|
+
@record = value_record = find_if_allowed(params[:id], :read)
|
143
143
|
return unless @record.authorized_for?(:crud_type => :update, :column => column)
|
144
|
+
if @column.delegated_association
|
145
|
+
value_record = @record.send(@column.delegated_association.name)
|
146
|
+
value_record ||= @record.association(@column.delegated_association.name).build
|
147
|
+
return unless value_record.authorized_for?(:crud_type => :update, :column => column)
|
148
|
+
end
|
144
149
|
|
145
150
|
value ||=
|
146
151
|
unless @column.column.nil? || @column.column.null
|
147
152
|
default_val = @column.column.default
|
148
|
-
default_val = @column.column
|
153
|
+
default_val = ActiveScaffold::Core.column_type_cast default_val, @column.column if Rails.version >= '4.2.0'
|
149
154
|
default_val == true ? false : default_val
|
150
155
|
end
|
151
156
|
unless @column.nil?
|
152
|
-
value = column_value_from_param_value(
|
153
|
-
value = [] if value.nil? && @column.form_ui && @column.
|
157
|
+
value = column_value_from_param_value(value_record, @column, value)
|
158
|
+
value = [] if value.nil? && @column.form_ui && @column.association.try(:collection?)
|
154
159
|
end
|
155
160
|
|
156
|
-
|
161
|
+
value_record.send("#{@column.name}=", value)
|
157
162
|
before_update_save(@record)
|
158
|
-
self.successful =
|
159
|
-
if
|
163
|
+
self.successful = value_record.save
|
164
|
+
if !successful?
|
165
|
+
flash.now[:error] = value_record.errors.full_messages.presence
|
166
|
+
elsif active_scaffold_config.actions.include?(:list)
|
160
167
|
if @column.inplace_edit_update == :table
|
161
168
|
params.delete(:id)
|
162
169
|
do_list
|
@@ -180,19 +187,19 @@ module ActiveScaffold::Actions
|
|
180
187
|
|
181
188
|
# The default security delegates to ActiveRecordPermissions.
|
182
189
|
# You may override the method to customize.
|
183
|
-
def update_authorized?(record = nil)
|
184
|
-
(!nested? || !nested.readonly?) && (record || self).authorized_for?(:
|
190
|
+
def update_authorized?(record = nil, column = nil)
|
191
|
+
(!nested? || !nested.readonly?) && (record || self).authorized_for?(crud_type: :update, column: column, reason: true)
|
185
192
|
end
|
186
193
|
|
187
194
|
def update_ignore?(record = nil)
|
188
|
-
!
|
195
|
+
!authorized_for?(:crud_type => :update)
|
189
196
|
end
|
190
197
|
|
191
198
|
private
|
192
199
|
|
193
200
|
def update_authorized_filter
|
194
201
|
link = active_scaffold_config.update.link || active_scaffold_config.update.class.link
|
195
|
-
raise ActiveScaffold::ActionNotAllowed unless send(link.security_method)
|
202
|
+
raise ActiveScaffold::ActionNotAllowed unless Array(send(link.security_method))[0]
|
196
203
|
end
|
197
204
|
|
198
205
|
def edit_formats
|
@@ -22,11 +22,15 @@ module ActiveScaffold
|
|
22
22
|
mattr_accessor :default_permission
|
23
23
|
@@default_permission = true
|
24
24
|
|
25
|
+
# if enabled, string returned on authorized methods will be interpreted as not authorized and used as reason
|
26
|
+
mattr_accessor :not_authorized_reason
|
27
|
+
@@not_authorized_reason = false
|
28
|
+
|
25
29
|
# This is a module aimed at making the current_user available to ActiveRecord models for permissions.
|
26
30
|
module ModelUserAccess
|
27
31
|
module Controller
|
28
32
|
def self.included(base)
|
29
|
-
base.
|
33
|
+
base.prepend_before_action :assign_current_user_to_models
|
30
34
|
end
|
31
35
|
|
32
36
|
# We need to give the ActiveRecord classes a handle to the current user. We don't want to just pass the object,
|
@@ -91,22 +95,37 @@ module ActiveScaffold
|
|
91
95
|
# options[:crud_type] should be a CRUD verb (:create, :read, :update, :destroy)
|
92
96
|
# options[:column] should be the name of a model attribute
|
93
97
|
# options[:action] is the name of a method
|
98
|
+
# options[:reason] if returning reason is expected, it will return array with authorized and reason, or nil if no reason
|
94
99
|
def authorized_for?(options = {})
|
95
|
-
raise ArgumentError, "unknown crud type #{options[:crud_type]}" if options[:crud_type] &&
|
100
|
+
raise ArgumentError, "unknown crud type #{options[:crud_type]}" if options[:crud_type] && !%i[create read update delete].include?(options[:crud_type])
|
96
101
|
|
102
|
+
not_authorized_reason = ActiveRecordPermissions.not_authorized_reason
|
97
103
|
# collect other possibly-related methods that actually exist
|
98
104
|
methods = cached_authorized_for_methods(options)
|
99
105
|
return ActiveRecordPermissions.default_permission if methods.empty?
|
100
|
-
|
106
|
+
if methods.one?
|
107
|
+
result = send(methods.first)
|
108
|
+
# if not_authorized_reason enabled interpret String as reason for not authorized
|
109
|
+
authorized, reason = not_authorized_reason && result.is_a?(String) ? [false, result] : result
|
110
|
+
# return array with reason only if requested with options[:reason]
|
111
|
+
return options[:reason] ? [authorized, reason] : authorized
|
112
|
+
end
|
101
113
|
|
102
114
|
# if any method returns false, then return false
|
103
|
-
|
115
|
+
methods.each do |method|
|
116
|
+
result = send(method)
|
117
|
+
# if not_authorized_reason enabled interpret String as reason for not authorized
|
118
|
+
authorized, reason = not_authorized_reason && result.is_a?(String) ? [false, result] : [result, nil]
|
119
|
+
next if authorized
|
120
|
+
# return array with reason only if requested with options[:reason]
|
121
|
+
return options[:reason] ? [authorized, reason] : authorized
|
122
|
+
end
|
104
123
|
true
|
105
124
|
end
|
106
125
|
|
107
126
|
def cached_authorized_for_methods(options)
|
108
127
|
key = "#{options[:crud_type]}##{options[:column]}##{options[:action]}"
|
109
|
-
if
|
128
|
+
if is_a? Class
|
110
129
|
self.class_security_methods ||= {}
|
111
130
|
self.class_security_methods[key] ||= authorized_for_methods(options)
|
112
131
|
else
|
@@ -33,26 +33,25 @@ module ActiveScaffold
|
|
33
33
|
module AttributeParams
|
34
34
|
protected
|
35
35
|
|
36
|
-
# workaround to update counters when belongs_to changes on persisted record on Rails 3
|
37
36
|
# workaround to update counters when polymorphic has_many changes on persisted record
|
38
|
-
# TODO: remove when
|
37
|
+
# TODO: remove when rails4 support is removed or counter cache for polymorphic has_many association works on rails4
|
39
38
|
def hack_for_has_many_counter_cache(parent_record, column, value)
|
40
39
|
association = parent_record.association(column.name)
|
41
40
|
counter_attr = association.send(:cached_counter_attribute_name)
|
42
41
|
difference = value.select(&:persisted?).size - parent_record.send(counter_attr)
|
43
42
|
|
44
43
|
if parent_record.new_record?
|
45
|
-
if Rails.version
|
44
|
+
if Rails.version >= '4.2.0'
|
46
45
|
parent_record.send "#{column.name}=", value
|
47
46
|
parent_record.send "#{counter_attr}_will_change!"
|
48
|
-
else # < 4.2
|
47
|
+
else # < 4.2
|
49
48
|
parent_record.send "#{counter_attr}=", difference
|
50
49
|
parent_record.send "#{column.name}=", value
|
51
50
|
end
|
52
51
|
else
|
53
52
|
# don't decrement counter for deleted records, on destroy they will update counter
|
54
53
|
difference += (parent_record.send(column.name) - value).size
|
55
|
-
association.send :update_counter, difference unless difference
|
54
|
+
association.send :update_counter, difference unless difference.zero?
|
56
55
|
end
|
57
56
|
|
58
57
|
# update counters on old parents if belongs_to is changed
|
@@ -63,21 +62,18 @@ module ActiveScaffold
|
|
63
62
|
parent_record.send "#{column.name}=", value if parent_record.persisted?
|
64
63
|
end
|
65
64
|
|
65
|
+
# rails 4 needs this hack for polymorphic has_many
|
66
66
|
# TODO: remove when hack_for_has_many_counter_cache is not needed
|
67
67
|
def hack_for_has_many_counter_cache?(parent_record, column)
|
68
|
-
|
69
|
-
if Rails.version < '4.0' # rails 3 needs this hack always
|
70
|
-
true
|
71
|
-
else # rails 4 needs this hack for polymorphic has_many
|
72
|
-
column.association.options[:as]
|
73
|
-
end
|
68
|
+
column.association.counter_cache_hack? && parent_record.association(column.name).send(:has_cached_counter?)
|
74
69
|
end
|
75
70
|
|
76
71
|
# workaround for updating counters twice bug on rails4 (https://github.com/rails/rails/pull/14849)
|
72
|
+
# rails 4 needs this hack for non-polymorphic belongs_to, when selecting record, not creating new one (value is Hash)
|
73
|
+
# rails 5 needs this hack for belongs_to, when selecting record, not creating new one (value is Hash)
|
77
74
|
# TODO: remove when pull request is merged and no version with bug is supported
|
78
|
-
def counter_cache_hack?(
|
79
|
-
|
80
|
-
column.association.try(:belongs_to?) && column.association.options[:counter_cache] && !column.association.options[:polymorphic]
|
75
|
+
def counter_cache_hack?(association, value)
|
76
|
+
!params_hash?(value) && association.belongs_to? && association.counter_cache_hack?
|
81
77
|
end
|
82
78
|
|
83
79
|
# Takes attributes (as from params[:record]) and applies them to the parent_record. Also looks for
|
@@ -110,7 +106,7 @@ module ActiveScaffold
|
|
110
106
|
value = update_column_from_params(parent_record, column, attributes[column.name], avoid_changes)
|
111
107
|
end
|
112
108
|
rescue => e
|
113
|
-
logger.error "#{e.class.name}: #{e.message} -- on the ActiveScaffold column = :#{column.name} for #{parent_record.inspect}#{" with value #{value}" if value}"
|
109
|
+
Rails.logger.error "#{e.class.name}: #{e.message} -- on the ActiveScaffold column = :#{column.name} for #{parent_record.inspect}#{" with value #{value}" if value}"
|
114
110
|
raise
|
115
111
|
end
|
116
112
|
end
|
@@ -120,14 +116,20 @@ module ActiveScaffold
|
|
120
116
|
|
121
117
|
def update_column_from_params(parent_record, column, attribute, avoid_changes = false)
|
122
118
|
value = column_value_from_param_value(parent_record, column, attribute, avoid_changes)
|
123
|
-
if avoid_changes && column.
|
119
|
+
if avoid_changes && column.association
|
124
120
|
parent_record.association(column.name).target = value
|
125
|
-
|
121
|
+
parent_record.send("#{column.association.foreign_key}=", value.try(:id)) if column.association.belongs_to?
|
122
|
+
elsif column.association && counter_cache_hack?(column.association, attribute)
|
126
123
|
parent_record.send "#{column.association.foreign_key}=", value.try(:id)
|
127
124
|
parent_record.association(column.name).target = value
|
125
|
+
elsif column.association.try(:collection?) && column.association.through? && !column.association.through_reflection.collection?
|
126
|
+
through = column.association.through_reflection.name
|
127
|
+
through_record = parent_record.send(through)
|
128
|
+
through_record ||= parent_record.send "build_#{through}"
|
129
|
+
through_record.send "#{column.association.source_reflection.name}=", value
|
128
130
|
else
|
129
131
|
begin
|
130
|
-
if hack_for_has_many_counter_cache?(parent_record, column)
|
132
|
+
if column.association && hack_for_has_many_counter_cache?(parent_record, column)
|
131
133
|
hack_for_has_many_counter_cache(parent_record, column, value)
|
132
134
|
else
|
133
135
|
parent_record.send "#{column.name}=", value
|
@@ -137,7 +139,7 @@ module ActiveScaffold
|
|
137
139
|
parent_record.association(column.name).target = value if column.association
|
138
140
|
end
|
139
141
|
end
|
140
|
-
if column.association
|
142
|
+
if column.association.try(:reverse_association).try(:belongs_to?)
|
141
143
|
Array(value).each { |v| v.send("#{column.association.reverse}=", parent_record) if v.new_record? }
|
142
144
|
end
|
143
145
|
value
|
@@ -146,10 +148,10 @@ module ActiveScaffold
|
|
146
148
|
def column_value_from_param_value(parent_record, column, value, avoid_changes = false)
|
147
149
|
# convert the value, possibly by instantiating associated objects
|
148
150
|
form_ui = column.form_ui || column.column.try(:type)
|
149
|
-
if form_ui &&
|
151
|
+
if form_ui && respond_to?("column_value_for_#{form_ui}_type", true)
|
150
152
|
send("column_value_for_#{form_ui}_type", parent_record, column, value)
|
151
|
-
elsif value
|
152
|
-
column_value_from_param_hash_value(parent_record, column, value, avoid_changes)
|
153
|
+
elsif params_hash? value
|
154
|
+
column_value_from_param_hash_value(parent_record, column, params_hash(value), avoid_changes)
|
153
155
|
else
|
154
156
|
column_value_from_param_simple_value(parent_record, column, value)
|
155
157
|
end
|
@@ -171,10 +173,14 @@ module ActiveScaffold
|
|
171
173
|
new_value
|
172
174
|
end
|
173
175
|
|
176
|
+
def column_value_for_month_type(parent_record, column, value)
|
177
|
+
Date.parse("#{value}-01")
|
178
|
+
end
|
179
|
+
|
174
180
|
def column_value_from_param_simple_value(parent_record, column, value)
|
175
|
-
if column.
|
181
|
+
if column.association.try :singular?
|
176
182
|
if value.present?
|
177
|
-
if column.
|
183
|
+
if column.association.polymorphic?
|
178
184
|
class_name = parent_record.send(column.association.foreign_type)
|
179
185
|
class_name.constantize.find(value) if class_name.present?
|
180
186
|
else
|
@@ -182,22 +188,23 @@ module ActiveScaffold
|
|
182
188
|
column.association.klass.find(value)
|
183
189
|
end
|
184
190
|
end
|
185
|
-
elsif column.
|
191
|
+
elsif column.association.try :collection?
|
186
192
|
column_plural_assocation_value_from_value(column, Array(value))
|
187
193
|
elsif column.number? && column.options[:format] && column.form_ui != :number
|
188
194
|
column.number_to_native(value)
|
189
195
|
else
|
190
196
|
# convert empty strings into nil. this works better with 'null => true' columns (and validations),
|
191
|
-
#
|
192
|
-
|
193
|
-
|
197
|
+
# for 'null => false' columns is just converted to default value from column
|
198
|
+
if value.is_a?(String) && value.empty? && !column.column.nil?
|
199
|
+
value = column.column.null ? nil : column.column.default
|
200
|
+
end
|
194
201
|
value
|
195
202
|
end
|
196
203
|
end
|
197
204
|
|
198
205
|
def column_plural_assocation_value_from_value(column, value)
|
199
206
|
# it's an array of ids
|
200
|
-
if value
|
207
|
+
if value.present?
|
201
208
|
ids = value.select(&:present?)
|
202
209
|
ids.empty? ? [] : column.association.klass.find(ids)
|
203
210
|
else
|
@@ -206,32 +213,35 @@ module ActiveScaffold
|
|
206
213
|
end
|
207
214
|
|
208
215
|
def column_value_from_param_hash_value(parent_record, column, value, avoid_changes = false)
|
209
|
-
if column.
|
216
|
+
if column.association.try :singular?
|
210
217
|
manage_nested_record_from_params(parent_record, column, value, avoid_changes)
|
211
|
-
elsif column.
|
218
|
+
elsif column.association.try :collection?
|
212
219
|
# HACK: to be able to delete all associated records, hash will include "0" => ""
|
213
|
-
value.
|
220
|
+
values = value.values.reject(&:blank?)
|
221
|
+
values.collect { |val| manage_nested_record_from_params(parent_record, column, val, avoid_changes) }.compact
|
214
222
|
else
|
215
223
|
value
|
216
224
|
end
|
217
225
|
end
|
218
226
|
|
219
227
|
def manage_nested_record_from_params(parent_record, column, attributes, avoid_changes = false)
|
220
|
-
return nil unless build_record_from_params(attributes, column, parent_record)
|
228
|
+
return nil unless build_record_from_params?(attributes, column, parent_record)
|
221
229
|
record = find_or_create_for_params(attributes, column, parent_record)
|
222
230
|
if record
|
223
231
|
record_columns = active_scaffold_config_for(column.association.klass).subform.columns
|
224
|
-
|
232
|
+
prev_constraints = record_columns.constraint_columns
|
233
|
+
record_columns.constraint_columns = [column.association.reverse].compact
|
225
234
|
update_record_from_params(record, record_columns, attributes, avoid_changes)
|
235
|
+
record_columns.constraint_columns = prev_constraints
|
226
236
|
record.unsaved = true
|
227
237
|
end
|
228
238
|
record
|
229
239
|
end
|
230
240
|
|
231
|
-
def build_record_from_params(params, column, record)
|
241
|
+
def build_record_from_params?(params, column, record)
|
232
242
|
current = record.send(column.name)
|
233
243
|
klass = column.association.klass
|
234
|
-
(column.
|
244
|
+
(column.association.collection? && !column.show_blank_record?(current)) || !attributes_hash_is_empty?(params, klass)
|
235
245
|
end
|
236
246
|
|
237
247
|
# Attempts to create or find an instance of the klass of the association in parent_column from the
|
@@ -261,12 +271,11 @@ module ActiveScaffold
|
|
261
271
|
end
|
262
272
|
end
|
263
273
|
|
264
|
-
def save_record_to_association(record,
|
265
|
-
association = record.class.reflect_on_association(association_name) if association_name
|
274
|
+
def save_record_to_association(record, association, value)
|
266
275
|
if association.try(:collection?)
|
267
|
-
record.send(
|
276
|
+
record.send(association.name) << value
|
268
277
|
elsif association
|
269
|
-
record.send("#{
|
278
|
+
record.send("#{association.name}=", value)
|
270
279
|
end
|
271
280
|
end
|
272
281
|
|
@@ -274,24 +283,26 @@ module ActiveScaffold
|
|
274
283
|
# This isn't a literal emptiness - it's an attempt to discern whether the user intended it to be empty or not.
|
275
284
|
def attributes_hash_is_empty?(hash, klass)
|
276
285
|
# old style date form management... ignore them too
|
277
|
-
part_ignore_column_types = [:datetime, :date, :time]
|
286
|
+
part_ignore_column_types = [:datetime, :date, :time, Time, Date]
|
278
287
|
|
279
288
|
hash.all? do |key, value|
|
280
289
|
# convert any possible multi-parameter attributes like 'created_at(5i)' to simply 'created_at'
|
281
290
|
parts = key.to_s.split('(')
|
282
291
|
column_name = parts.first
|
283
|
-
column =
|
292
|
+
column = ActiveScaffold::OrmChecks.columns_hash(klass)[column_name]
|
293
|
+
column_type = ActiveScaffold::OrmChecks.column_type(klass, column_name) if column
|
284
294
|
|
285
|
-
#
|
295
|
+
# datetimes will always have a value. so we ignore them when checking whether the hash is empty.
|
286
296
|
# this could be a bad idea. but the current situation (excess record entry) seems worse.
|
287
|
-
next true if column && parts.length > 1 && part_ignore_column_types.include?(
|
297
|
+
next true if column && parts.length > 1 && part_ignore_column_types.include?(column_type)
|
288
298
|
|
289
299
|
# defaults are pre-filled on the form. we can't use them to determine if the user intends a new row.
|
300
|
+
# booleans always have value, so they are ignored if not changed from default
|
290
301
|
default_value = column_default_value(column_name, klass, column)
|
291
302
|
casted_value = column ? ActiveScaffold::Core.column_type_cast(value, column) : value
|
292
303
|
next true if casted_value == default_value
|
293
304
|
|
294
|
-
if value
|
305
|
+
if params_hash? value
|
295
306
|
attributes_hash_is_empty?(value, klass)
|
296
307
|
elsif value.is_a?(Array)
|
297
308
|
value.all?(&:blank?)
|
@@ -303,10 +314,18 @@ module ActiveScaffold
|
|
303
314
|
|
304
315
|
def column_default_value(column_name, klass, column)
|
305
316
|
return unless column
|
306
|
-
if
|
307
|
-
column.
|
308
|
-
|
309
|
-
|
317
|
+
if ActiveScaffold::OrmChecks.mongoid? klass
|
318
|
+
column.default_val
|
319
|
+
elsif ActiveScaffold::OrmChecks.active_record? klass
|
320
|
+
if Rails.version < '4.2'
|
321
|
+
column.default
|
322
|
+
elsif Rails.version < '5.0'
|
323
|
+
column.type_cast_from_database(column.default)
|
324
|
+
else
|
325
|
+
column_type = ActiveScaffold::OrmChecks.column_type(klass, column_name)
|
326
|
+
cast_type = ActiveModel::Type.lookup column_type
|
327
|
+
cast_type ? cast_type.deserialize(column.default) : column.default
|
328
|
+
end
|
310
329
|
end
|
311
330
|
end
|
312
331
|
end
|