active_scaffold 3.0.0
Sign up to get free protection for your applications and to get access to all the features.
- data/.autotest +27 -0
- data/CHANGELOG +152 -0
- data/Gemfile +4 -0
- data/MIT-LICENSE +20 -0
- data/README +51 -0
- data/Rakefile +24 -0
- data/active_scaffold.gemspec +24 -0
- data/environment.rb +22 -0
- data/frontends/default/images/add.gif +0 -0
- data/frontends/default/images/arrow_down.gif +0 -0
- data/frontends/default/images/arrow_up.gif +0 -0
- data/frontends/default/images/close.gif +0 -0
- data/frontends/default/images/cross.png +0 -0
- data/frontends/default/images/indicator-small.gif +0 -0
- data/frontends/default/images/indicator.gif +0 -0
- data/frontends/default/images/magnifier.png +0 -0
- data/frontends/default/javascripts/jquery/active_scaffold.js +957 -0
- data/frontends/default/javascripts/jquery/jquery.editinplace.js +726 -0
- data/frontends/default/javascripts/prototype/active_scaffold.js +954 -0
- data/frontends/default/javascripts/prototype/dhtml_history.js +867 -0
- data/frontends/default/javascripts/prototype/form_enhancements.js +117 -0
- data/frontends/default/javascripts/prototype/rico_corner.js +370 -0
- data/frontends/default/stylesheets/stylesheet-ie.css +35 -0
- data/frontends/default/stylesheets/stylesheet.css +858 -0
- data/frontends/default/views/_add_existing_form.html.erb +30 -0
- data/frontends/default/views/_base_form.html.erb +41 -0
- data/frontends/default/views/_create_form.html.erb +6 -0
- data/frontends/default/views/_create_form_on_list.html.erb +5 -0
- data/frontends/default/views/_field_search.html.erb +32 -0
- data/frontends/default/views/_form.html.erb +24 -0
- data/frontends/default/views/_form_association.html.erb +14 -0
- data/frontends/default/views/_form_association_footer.html.erb +40 -0
- data/frontends/default/views/_form_attribute.html.erb +15 -0
- data/frontends/default/views/_form_hidden_attribute.html.erb +2 -0
- data/frontends/default/views/_form_messages.html.erb +5 -0
- data/frontends/default/views/_horizontal_subform.html.erb +19 -0
- data/frontends/default/views/_horizontal_subform_header.html.erb +10 -0
- data/frontends/default/views/_horizontal_subform_record.html.erb +37 -0
- data/frontends/default/views/_human_conditions.html.erb +1 -0
- data/frontends/default/views/_list.html.erb +18 -0
- data/frontends/default/views/_list_actions.html.erb +16 -0
- data/frontends/default/views/_list_calculations.html.erb +16 -0
- data/frontends/default/views/_list_column_headings.html.erb +12 -0
- data/frontends/default/views/_list_header.html.erb +12 -0
- data/frontends/default/views/_list_inline_adapter.html.erb +10 -0
- data/frontends/default/views/_list_messages.html.erb +32 -0
- data/frontends/default/views/_list_pagination.html.erb +11 -0
- data/frontends/default/views/_list_pagination_links.html.erb +9 -0
- data/frontends/default/views/_list_record.html.erb +14 -0
- data/frontends/default/views/_list_record_columns.html.erb +8 -0
- data/frontends/default/views/_list_with_header.html.erb +32 -0
- data/frontends/default/views/_messages.html.erb +10 -0
- data/frontends/default/views/_render_field.js.rjs +13 -0
- data/frontends/default/views/_row.html.erb +12 -0
- data/frontends/default/views/_search.html.erb +34 -0
- data/frontends/default/views/_search_attribute.html.erb +10 -0
- data/frontends/default/views/_show.html.erb +8 -0
- data/frontends/default/views/_show_columns.html.erb +12 -0
- data/frontends/default/views/_update_actions.html.erb +9 -0
- data/frontends/default/views/_update_form.html.erb +5 -0
- data/frontends/default/views/_vertical_subform.html.erb +12 -0
- data/frontends/default/views/_vertical_subform_record.html.erb +38 -0
- data/frontends/default/views/add_existing.js.rjs +17 -0
- data/frontends/default/views/add_existing_form.html.erb +5 -0
- data/frontends/default/views/create.html.erb +5 -0
- data/frontends/default/views/delete.html.erb +13 -0
- data/frontends/default/views/destroy.js.rjs +5 -0
- data/frontends/default/views/edit_associated.js.rjs +11 -0
- data/frontends/default/views/field_search.html.erb +5 -0
- data/frontends/default/views/form_messages.js.rjs +1 -0
- data/frontends/default/views/list.html.erb +1 -0
- data/frontends/default/views/list.js.rjs +1 -0
- data/frontends/default/views/on_action_update.js.rjs +8 -0
- data/frontends/default/views/on_create.js.rjs +24 -0
- data/frontends/default/views/on_update.js.rjs +15 -0
- data/frontends/default/views/search.html.erb +5 -0
- data/frontends/default/views/show.html.erb +5 -0
- data/frontends/default/views/update.html.erb +8 -0
- data/frontends/default/views/update_column.js.rjs +13 -0
- data/frontends/default/views/update_row.js.rjs +1 -0
- data/init.rb +1 -0
- data/install_assets.rb +44 -0
- data/lib/active_record_permissions.rb +134 -0
- data/lib/active_scaffold.rb +279 -0
- data/lib/active_scaffold/actions/common_search.rb +22 -0
- data/lib/active_scaffold/actions/core.rb +150 -0
- data/lib/active_scaffold/actions/create.rb +152 -0
- data/lib/active_scaffold/actions/delete.rb +72 -0
- data/lib/active_scaffold/actions/field_search.rb +82 -0
- data/lib/active_scaffold/actions/list.rb +128 -0
- data/lib/active_scaffold/actions/mark.rb +50 -0
- data/lib/active_scaffold/actions/nested.rb +241 -0
- data/lib/active_scaffold/actions/search.rb +47 -0
- data/lib/active_scaffold/actions/show.rb +54 -0
- data/lib/active_scaffold/actions/subform.rb +17 -0
- data/lib/active_scaffold/actions/update.rb +134 -0
- data/lib/active_scaffold/attribute_params.rb +207 -0
- data/lib/active_scaffold/bridges/ancestry/bridge.rb +5 -0
- data/lib/active_scaffold/bridges/ancestry/lib/ancestry_bridge.rb +38 -0
- data/lib/active_scaffold/bridges/bridge.rb +52 -0
- data/lib/active_scaffold/bridges/calendar_date_select/bridge.rb +16 -0
- data/lib/active_scaffold/bridges/calendar_date_select/lib/as_cds_bridge.rb +79 -0
- data/lib/active_scaffold/bridges/carrierwave/bridge.rb +7 -0
- data/lib/active_scaffold/bridges/carrierwave/lib/carrierwave_bridge.rb +38 -0
- data/lib/active_scaffold/bridges/carrierwave/lib/carrierwave_bridge_helpers.rb +26 -0
- data/lib/active_scaffold/bridges/carrierwave/lib/form_ui.rb +35 -0
- data/lib/active_scaffold/bridges/carrierwave/lib/list_ui.rb +17 -0
- data/lib/active_scaffold/bridges/date_picker/bridge.rb +22 -0
- data/lib/active_scaffold/bridges/date_picker/lib/datepicker_bridge.rb +225 -0
- data/lib/active_scaffold/bridges/date_picker/public/javascripts/date_picker_bridge.js +22 -0
- data/lib/active_scaffold/bridges/file_column/bridge.rb +11 -0
- data/lib/active_scaffold/bridges/file_column/lib/as_file_column_bridge.rb +46 -0
- data/lib/active_scaffold/bridges/file_column/lib/file_column_helpers.rb +59 -0
- data/lib/active_scaffold/bridges/file_column/lib/form_ui.rb +37 -0
- data/lib/active_scaffold/bridges/file_column/lib/list_ui.rb +26 -0
- data/lib/active_scaffold/bridges/file_column/test/functional/file_column_keep_test.rb +43 -0
- data/lib/active_scaffold/bridges/file_column/test/mock_model.rb +9 -0
- data/lib/active_scaffold/bridges/file_column/test/test_helper.rb +15 -0
- data/lib/active_scaffold/bridges/paperclip/bridge.rb +12 -0
- data/lib/active_scaffold/bridges/paperclip/lib/form_ui.rb +27 -0
- data/lib/active_scaffold/bridges/paperclip/lib/list_ui.rb +16 -0
- data/lib/active_scaffold/bridges/paperclip/lib/paperclip_bridge.rb +38 -0
- data/lib/active_scaffold/bridges/paperclip/lib/paperclip_bridge_helpers.rb +26 -0
- data/lib/active_scaffold/bridges/semantic_attributes/bridge.rb +5 -0
- data/lib/active_scaffold/bridges/semantic_attributes/lib/semantic_attributes_bridge.rb +20 -0
- data/lib/active_scaffold/bridges/shared/date_bridge.rb +187 -0
- data/lib/active_scaffold/bridges/tiny_mce/bridge.rb +5 -0
- data/lib/active_scaffold/bridges/tiny_mce/lib/tiny_mce_bridge.rb +45 -0
- data/lib/active_scaffold/bridges/validation_reflection/bridge.rb +8 -0
- data/lib/active_scaffold/bridges/validation_reflection/lib/validation_reflection_bridge.rb +21 -0
- data/lib/active_scaffold/config/base.rb +54 -0
- data/lib/active_scaffold/config/core.rb +229 -0
- data/lib/active_scaffold/config/create.rb +43 -0
- data/lib/active_scaffold/config/delete.rb +25 -0
- data/lib/active_scaffold/config/field_search.rb +74 -0
- data/lib/active_scaffold/config/form.rb +46 -0
- data/lib/active_scaffold/config/list.rb +174 -0
- data/lib/active_scaffold/config/mark.rb +22 -0
- data/lib/active_scaffold/config/nested.rb +43 -0
- data/lib/active_scaffold/config/search.rb +68 -0
- data/lib/active_scaffold/config/show.rb +34 -0
- data/lib/active_scaffold/config/subform.rb +35 -0
- data/lib/active_scaffold/config/update.rb +38 -0
- data/lib/active_scaffold/configurable.rb +29 -0
- data/lib/active_scaffold/constraints.rb +179 -0
- data/lib/active_scaffold/data_structures/action_columns.rb +133 -0
- data/lib/active_scaffold/data_structures/action_link.rb +162 -0
- data/lib/active_scaffold/data_structures/action_links.rb +59 -0
- data/lib/active_scaffold/data_structures/actions.rb +45 -0
- data/lib/active_scaffold/data_structures/column.rb +348 -0
- data/lib/active_scaffold/data_structures/columns.rb +75 -0
- data/lib/active_scaffold/data_structures/error_message.rb +24 -0
- data/lib/active_scaffold/data_structures/nested_info.rb +108 -0
- data/lib/active_scaffold/data_structures/set.rb +62 -0
- data/lib/active_scaffold/data_structures/sorting.rb +168 -0
- data/lib/active_scaffold/finder.rb +333 -0
- data/lib/active_scaffold/helpers/association_helpers.rb +40 -0
- data/lib/active_scaffold/helpers/controller_helpers.rb +40 -0
- data/lib/active_scaffold/helpers/country_helpers.rb +352 -0
- data/lib/active_scaffold/helpers/form_column_helpers.rb +343 -0
- data/lib/active_scaffold/helpers/human_condition_helpers.rb +59 -0
- data/lib/active_scaffold/helpers/id_helpers.rb +131 -0
- data/lib/active_scaffold/helpers/list_column_helpers.rb +363 -0
- data/lib/active_scaffold/helpers/pagination_helpers.rb +55 -0
- data/lib/active_scaffold/helpers/search_column_helpers.rb +238 -0
- data/lib/active_scaffold/helpers/show_column_helpers.rb +46 -0
- data/lib/active_scaffold/helpers/view_helpers.rb +315 -0
- data/lib/active_scaffold/locale/de.rb +113 -0
- data/lib/active_scaffold/locale/en.rb +118 -0
- data/lib/active_scaffold/locale/es.yml +112 -0
- data/lib/active_scaffold/locale/fr.rb +113 -0
- data/lib/active_scaffold/locale/hu.yml +63 -0
- data/lib/active_scaffold/locale/ja.yml +64 -0
- data/lib/active_scaffold/locale/ru.yml +62 -0
- data/lib/active_scaffold/marked_model.rb +38 -0
- data/lib/dhtml_confirm.rb +54 -0
- data/lib/extensions/action_controller_rendering.rb +20 -0
- data/lib/extensions/action_view_rendering.rb +113 -0
- data/lib/extensions/action_view_resolver.rb +7 -0
- data/lib/extensions/active_record_offset.rb +12 -0
- data/lib/extensions/array.rb +7 -0
- data/lib/extensions/localize.rb +10 -0
- data/lib/extensions/name_option_for_datetime.rb +12 -0
- data/lib/extensions/nil_id_in_url_params.rb +7 -0
- data/lib/extensions/paginator_extensions.rb +26 -0
- data/lib/extensions/reverse_associations.rb +62 -0
- data/lib/extensions/routing_mapper.rb +34 -0
- data/lib/extensions/to_label.rb +8 -0
- data/lib/extensions/unsaved_associated.rb +61 -0
- data/lib/extensions/unsaved_record.rb +20 -0
- data/lib/extensions/usa_state.rb +46 -0
- data/lib/generators/active_scaffold/USAGE +29 -0
- data/lib/generators/active_scaffold/active_scaffold_generator.rb +20 -0
- data/lib/generators/active_scaffold_controller/USAGE +19 -0
- data/lib/generators/active_scaffold_controller/active_scaffold_controller_generator.rb +28 -0
- data/lib/generators/active_scaffold_controller/templates/controller.rb +4 -0
- data/lib/generators/active_scaffold_setup/USAGE +10 -0
- data/lib/generators/active_scaffold_setup/active_scaffold_setup_generator.rb +53 -0
- data/lib/paginator.rb +136 -0
- data/lib/responds_to_parent.rb +70 -0
- data/public/blank.html +33 -0
- data/shoulda_macros/macros.rb +136 -0
- data/test/bridges/bridge_test.rb +47 -0
- data/test/config/base_test.rb +15 -0
- data/test/config/create_test.rb +55 -0
- data/test/config/list_test.rb +74 -0
- data/test/config/show_test.rb +43 -0
- data/test/config/update_test.rb +17 -0
- data/test/const_mocker.rb +36 -0
- data/test/data_structures/action_columns_test.rb +113 -0
- data/test/data_structures/action_link_test.rb +78 -0
- data/test/data_structures/action_links_test.rb +78 -0
- data/test/data_structures/actions_test.rb +25 -0
- data/test/data_structures/association_column_test.rb +42 -0
- data/test/data_structures/column_test.rb +185 -0
- data/test/data_structures/columns_test.rb +69 -0
- data/test/data_structures/error_message_test.rb +28 -0
- data/test/data_structures/set_test.rb +86 -0
- data/test/data_structures/sorting_test.rb +126 -0
- data/test/data_structures/standard_column_test.rb +24 -0
- data/test/data_structures/virtual_column_test.rb +23 -0
- data/test/extensions/active_record_test.rb +45 -0
- data/test/extensions/array_test.rb +12 -0
- data/test/helpers/form_column_helpers_test.rb +31 -0
- data/test/helpers/list_column_helpers_test.rb +31 -0
- data/test/helpers/pagination_helpers_test.rb +55 -0
- data/test/misc/active_record_permissions_test.rb +154 -0
- data/test/misc/attribute_params_test.rb +110 -0
- data/test/misc/configurable_test.rb +96 -0
- data/test/misc/constraints_test.rb +193 -0
- data/test/misc/finder_test.rb +93 -0
- data/test/misc/lang_test.rb +12 -0
- data/test/mock_app/.gitignore +2 -0
- data/test/mock_app/app/controllers/application_controller.rb +10 -0
- data/test/mock_app/app/helpers/application_helper.rb +3 -0
- data/test/mock_app/config/boot.rb +110 -0
- data/test/mock_app/config/database.yml +16 -0
- data/test/mock_app/config/environment.rb +43 -0
- data/test/mock_app/config/environments/development.rb +17 -0
- data/test/mock_app/config/environments/production.rb +28 -0
- data/test/mock_app/config/environments/test.rb +28 -0
- data/test/mock_app/config/initializers/backtrace_silencers.rb +7 -0
- data/test/mock_app/config/initializers/inflections.rb +10 -0
- data/test/mock_app/config/initializers/mime_types.rb +5 -0
- data/test/mock_app/config/initializers/new_rails_defaults.rb +19 -0
- data/test/mock_app/config/initializers/session_store.rb +15 -0
- data/test/mock_app/config/locales/en.yml +5 -0
- data/test/mock_app/config/routes.rb +43 -0
- data/test/mock_app/db/test.sqlite3 +1 -0
- data/test/mock_app/public/blank.html +33 -0
- data/test/mock_app/public/images/active_scaffold/DO_NOT_EDIT +2 -0
- data/test/mock_app/public/images/active_scaffold/default/add.gif +0 -0
- data/test/mock_app/public/images/active_scaffold/default/arrow_down.gif +0 -0
- data/test/mock_app/public/images/active_scaffold/default/arrow_up.gif +0 -0
- data/test/mock_app/public/images/active_scaffold/default/close.gif +0 -0
- data/test/mock_app/public/images/active_scaffold/default/cross.png +0 -0
- data/test/mock_app/public/images/active_scaffold/default/indicator-small.gif +0 -0
- data/test/mock_app/public/images/active_scaffold/default/indicator.gif +0 -0
- data/test/mock_app/public/images/active_scaffold/default/magnifier.png +0 -0
- data/test/mock_app/public/javascripts/active_scaffold/DO_NOT_EDIT +2 -0
- data/test/mock_app/public/javascripts/active_scaffold/default/active_scaffold.js +532 -0
- data/test/mock_app/public/javascripts/active_scaffold/default/dhtml_history.js +867 -0
- data/test/mock_app/public/javascripts/active_scaffold/default/form_enhancements.js +117 -0
- data/test/mock_app/public/javascripts/active_scaffold/default/rico_corner.js +370 -0
- data/test/mock_app/public/stylesheets/active_scaffold/DO_NOT_EDIT +2 -0
- data/test/mock_app/public/stylesheets/active_scaffold/default/stylesheet-ie.css +35 -0
- data/test/mock_app/public/stylesheets/active_scaffold/default/stylesheet.css +839 -0
- data/test/model_stub.rb +55 -0
- data/test/run_all.rb +8 -0
- data/test/test_helper.rb +39 -0
- data/uninstall.rb +13 -0
- metadata +478 -0
@@ -0,0 +1,134 @@
|
|
1
|
+
# This module attempts to create permissions conventions for your ActiveRecord models. It supports english-based
|
2
|
+
# methods that let you restrict access per-model, per-record, per-column, per-action, and per-user. All at once.
|
3
|
+
#
|
4
|
+
# You may define instance methods in the following formats:
|
5
|
+
# def #{column}_authorized_for_#{action}?
|
6
|
+
# def #{column}_authorized?
|
7
|
+
# def authorized_for_#{action}?
|
8
|
+
#
|
9
|
+
# Your methods should allow for the following special cases:
|
10
|
+
# * cron scripts
|
11
|
+
# * guest users (or nil current_user objects)
|
12
|
+
module ActiveRecordPermissions
|
13
|
+
# ActiveRecordPermissions needs to know what method on your ApplicationController will return the current user,
|
14
|
+
# if available. This defaults to the :current_user method. You may configure this in your environment.rb if you
|
15
|
+
# have a different setup.
|
16
|
+
def self.current_user_method=(v); @@current_user_method = v; end
|
17
|
+
def self.current_user_method; @@current_user_method; end
|
18
|
+
@@current_user_method = :current_user
|
19
|
+
|
20
|
+
# Whether the default permission is permissive or not
|
21
|
+
# If set to true, then everything's allowed until configured otherwise
|
22
|
+
def self.default_permission=(v); @@default_permission = v; end
|
23
|
+
def self.default_permission; @@default_permission; end
|
24
|
+
@@default_permission = true
|
25
|
+
|
26
|
+
# This is a module aimed at making the current_user available to ActiveRecord models for permissions.
|
27
|
+
module ModelUserAccess
|
28
|
+
module Controller
|
29
|
+
def self.included(base)
|
30
|
+
base.prepend_before_filter :assign_current_user_to_models
|
31
|
+
end
|
32
|
+
|
33
|
+
# We need to give the ActiveRecord classes a handle to the current user. We don't want to just pass the object,
|
34
|
+
# because the object may change (someone may log in or out). So we give ActiveRecord a proc that ties to the
|
35
|
+
# current_user_method on this ApplicationController.
|
36
|
+
def assign_current_user_to_models
|
37
|
+
ActiveRecord::Base.current_user_proc = proc {send(ActiveRecordPermissions.current_user_method)}
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
module Model
|
42
|
+
def self.included(base)
|
43
|
+
base.extend ClassMethods
|
44
|
+
end
|
45
|
+
|
46
|
+
module ClassMethods
|
47
|
+
# The proc to call that retrieves the current_user from the ApplicationController.
|
48
|
+
attr_accessor :current_user_proc
|
49
|
+
|
50
|
+
# Class-level access to the current user
|
51
|
+
def current_user
|
52
|
+
ActiveRecord::Base.current_user_proc.call if ActiveRecord::Base.current_user_proc
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
# Instance-level access to the current user
|
57
|
+
def current_user
|
58
|
+
self.class.current_user
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
module Permissions
|
64
|
+
def self.included(base)
|
65
|
+
base.extend SecurityMethods
|
66
|
+
base.send :include, SecurityMethods
|
67
|
+
end
|
68
|
+
|
69
|
+
# Because any class-level queries get delegated to the instance level via a new record,
|
70
|
+
# it's useful to know when the authorization query is meant for a specific record or not.
|
71
|
+
# But using new_record? is confusing, even though accurate. So this is basically just a wrapper.
|
72
|
+
def existing_record_check?
|
73
|
+
!new_record?
|
74
|
+
end
|
75
|
+
|
76
|
+
module SecurityMethods
|
77
|
+
# A generic authorization query. This is what will be called programatically, since
|
78
|
+
# the actual permission methods can't be guaranteed to exist. And because we want to
|
79
|
+
# intelligently combine multiple applicable methods.
|
80
|
+
#
|
81
|
+
# options[:crud_type] should be a CRUD verb (:create, :read, :update, :destroy)
|
82
|
+
# options[:column] should be the name of a model attribute
|
83
|
+
# options[:action] is the name of a method
|
84
|
+
def authorized_for?(options = {})
|
85
|
+
raise ArgumentError, "unknown crud type #{options[:crud_type]}" if options[:crud_type] and ![:create, :read, :update, :delete].include?(options[:crud_type])
|
86
|
+
|
87
|
+
# column_authorized_for_crud_type? has the highest priority over other methods,
|
88
|
+
# you can disable a crud verb and enable that verb for a column
|
89
|
+
# (for example, disable update and enable inplace_edit in a column)
|
90
|
+
method = column_and_crud_type_security_method(options[:column], options[:crud_type])
|
91
|
+
return send(method) if method and respond_to?(method)
|
92
|
+
|
93
|
+
# authorized_for_action? has higher priority than other methods,
|
94
|
+
# you can disable a crud verb and enable an action with that crud verb
|
95
|
+
# (for example, disable update and enable an action with update as crud type)
|
96
|
+
method = action_security_method(options[:action])
|
97
|
+
return send(method) if method and respond_to?(method)
|
98
|
+
|
99
|
+
# collect other possibly-related methods that actually exist
|
100
|
+
methods = [
|
101
|
+
column_security_method(options[:column]),
|
102
|
+
crud_type_security_method(options[:crud_type]),
|
103
|
+
].compact.select {|m| respond_to?(m)}
|
104
|
+
|
105
|
+
# if any method returns false, then return false
|
106
|
+
return false if methods.any? {|m| !send(m)}
|
107
|
+
|
108
|
+
# if any method actually exists then it must've returned true, so return true
|
109
|
+
return true unless methods.empty?
|
110
|
+
|
111
|
+
# if no method exists, return the default permission
|
112
|
+
return ActiveRecordPermissions.default_permission
|
113
|
+
end
|
114
|
+
|
115
|
+
private
|
116
|
+
|
117
|
+
def column_security_method(column)
|
118
|
+
"#{column}_authorized?" if column
|
119
|
+
end
|
120
|
+
|
121
|
+
def crud_type_security_method(crud_type)
|
122
|
+
"authorized_for_#{crud_type}?" if crud_type
|
123
|
+
end
|
124
|
+
|
125
|
+
def action_security_method(action)
|
126
|
+
"authorized_for_#{action}?" if action
|
127
|
+
end
|
128
|
+
|
129
|
+
def column_and_crud_type_security_method(column, crud_type)
|
130
|
+
"#{column}_authorized_for_#{crud_type}?" if column and crud_type
|
131
|
+
end
|
132
|
+
end
|
133
|
+
end
|
134
|
+
end
|
@@ -0,0 +1,279 @@
|
|
1
|
+
require 'active_record_permissions'
|
2
|
+
require 'dhtml_confirm'
|
3
|
+
require 'paginator'
|
4
|
+
require 'responds_to_parent'
|
5
|
+
require 'active_scaffold/attribute_params'
|
6
|
+
require 'active_scaffold/configurable'
|
7
|
+
require 'active_scaffold/constraints'
|
8
|
+
require 'active_scaffold/finder'
|
9
|
+
require 'active_scaffold/marked_model'
|
10
|
+
require 'active_scaffold/config/base'
|
11
|
+
require 'active_scaffold/data_structures/column'
|
12
|
+
require 'active_scaffold/data_structures/actions'
|
13
|
+
require 'active_scaffold/data_structures/action_links'
|
14
|
+
require 'active_scaffold/config/form'
|
15
|
+
|
16
|
+
module ActiveScaffold
|
17
|
+
class ControllerNotFound < RuntimeError; end
|
18
|
+
class DependencyFailure < RuntimeError; end
|
19
|
+
class MalformedConstraint < RuntimeError; end
|
20
|
+
class RecordNotAllowed < SecurityError; end
|
21
|
+
class ActionNotAllowed < SecurityError; end
|
22
|
+
class ReverseAssociationRequired < RuntimeError; end
|
23
|
+
|
24
|
+
def self.included(base)
|
25
|
+
base.extend(ClassMethods)
|
26
|
+
base.module_eval do
|
27
|
+
# TODO: these should be in actions/core
|
28
|
+
before_filter :handle_user_settings
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
def self.set_defaults(&block)
|
33
|
+
ActiveScaffold::Config::Core.configure &block
|
34
|
+
end
|
35
|
+
|
36
|
+
def active_scaffold_config
|
37
|
+
self.class.active_scaffold_config
|
38
|
+
end
|
39
|
+
|
40
|
+
def active_scaffold_config_for(klass)
|
41
|
+
self.class.active_scaffold_config_for(klass)
|
42
|
+
end
|
43
|
+
|
44
|
+
def active_scaffold_session_storage
|
45
|
+
id = params[:eid] || params[:controller]
|
46
|
+
session_index = "as:#{id}"
|
47
|
+
session[session_index] ||= {}
|
48
|
+
session[session_index]
|
49
|
+
end
|
50
|
+
|
51
|
+
# at some point we need to pass the session and params into config. we'll just take care of that before any particular action occurs by passing those hashes off to the UserSettings class of each action.
|
52
|
+
def handle_user_settings
|
53
|
+
if self.class.uses_active_scaffold?
|
54
|
+
active_scaffold_config.actions.each do |action_name|
|
55
|
+
conf_instance = active_scaffold_config.send(action_name) rescue next
|
56
|
+
next if conf_instance.class::UserSettings == ActiveScaffold::Config::Base::UserSettings # if it hasn't been extended, skip it
|
57
|
+
active_scaffold_session_storage[action_name] ||= {}
|
58
|
+
conf_instance.user = conf_instance.class::UserSettings.new(conf_instance, active_scaffold_session_storage[action_name], params)
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
def self.js_framework=(framework)
|
64
|
+
@@js_framework = framework
|
65
|
+
end
|
66
|
+
|
67
|
+
def self.js_framework
|
68
|
+
@@js_framework ||= :prototype
|
69
|
+
end
|
70
|
+
|
71
|
+
module ClassMethods
|
72
|
+
def active_scaffold(model_id = nil, &block)
|
73
|
+
# initialize bridges here
|
74
|
+
ActiveScaffold::Bridges::Bridge.run_all
|
75
|
+
|
76
|
+
# converts Foo::BarController to 'bar' and FooBarsController to 'foo_bar' and AddressController to 'address'
|
77
|
+
model_id = self.to_s.split('::').last.sub(/Controller$/, '').pluralize.singularize.underscore unless model_id
|
78
|
+
|
79
|
+
# run the configuration
|
80
|
+
@active_scaffold_config = ActiveScaffold::Config::Core.new(model_id)
|
81
|
+
@active_scaffold_config_block = block
|
82
|
+
self.links_for_associations
|
83
|
+
|
84
|
+
@active_scaffold_overrides = []
|
85
|
+
ActionController::Base.view_paths.each do |dir|
|
86
|
+
active_scaffold_overrides_dir = File.join(dir.to_s,"active_scaffold_overrides")
|
87
|
+
@active_scaffold_overrides << active_scaffold_overrides_dir if File.exists?(active_scaffold_overrides_dir)
|
88
|
+
end
|
89
|
+
@active_scaffold_overrides.uniq! # Fix rails duplicating some view_paths
|
90
|
+
@active_scaffold_frontends = []
|
91
|
+
if active_scaffold_config.frontend.to_sym != :default
|
92
|
+
active_scaffold_custom_frontend_path = File.join(ActiveScaffold::Config::Core.plugin_directory, 'frontends', active_scaffold_config.frontend.to_s , 'views')
|
93
|
+
@active_scaffold_frontends << active_scaffold_custom_frontend_path
|
94
|
+
end
|
95
|
+
active_scaffold_default_frontend_path = File.join(ActiveScaffold::Config::Core.plugin_directory, 'frontends', 'default' , 'views')
|
96
|
+
@active_scaffold_frontends << active_scaffold_default_frontend_path
|
97
|
+
@active_scaffold_custom_paths = []
|
98
|
+
|
99
|
+
self.active_scaffold_superclasses_blocks.each {|superblock| self.active_scaffold_config.configure &superblock}
|
100
|
+
self.active_scaffold_config.configure &block if block_given?
|
101
|
+
self.active_scaffold_config._configure_sti unless self.active_scaffold_config.sti_children.nil?
|
102
|
+
self.active_scaffold_config._load_action_columns
|
103
|
+
|
104
|
+
# defines the attribute read methods on the model, so record.send() doesn't find protected/private methods instead
|
105
|
+
klass = self.active_scaffold_config.model
|
106
|
+
klass.define_attribute_methods unless klass.attribute_methods_generated?
|
107
|
+
# include the rest of the code into the controller: the action core and the included actions
|
108
|
+
module_eval do
|
109
|
+
include ActiveScaffold::Finder
|
110
|
+
include ActiveScaffold::Constraints
|
111
|
+
include ActiveScaffold::AttributeParams
|
112
|
+
include ActiveScaffold::Actions::Core
|
113
|
+
active_scaffold_config.actions.each do |mod|
|
114
|
+
name = mod.to_s.camelize
|
115
|
+
include "ActiveScaffold::Actions::#{name}".constantize
|
116
|
+
|
117
|
+
# sneak the action links from the actions into the main set
|
118
|
+
if link = active_scaffold_config.send(mod).link rescue nil
|
119
|
+
active_scaffold_config.action_links << link
|
120
|
+
end
|
121
|
+
end
|
122
|
+
end
|
123
|
+
active_scaffold_paths.each do |path|
|
124
|
+
self.append_view_path(ActionView::ActiveScaffoldResolver.new(path))
|
125
|
+
end
|
126
|
+
self.active_scaffold_config._add_sti_create_links if self.active_scaffold_config.add_sti_create_links?
|
127
|
+
end
|
128
|
+
|
129
|
+
# Create the automatic column links. Note that this has to happen when configuration is *done*, because otherwise the Nested module could be disabled. Actually, it could still be disabled later, couldn't it?
|
130
|
+
def links_for_associations
|
131
|
+
return unless active_scaffold_config.actions.include? :list and active_scaffold_config.actions.include? :nested
|
132
|
+
active_scaffold_config.columns.each do |column|
|
133
|
+
next unless column.link.nil? and column.autolink?
|
134
|
+
action_link = link_for_association(column)
|
135
|
+
column.set_link(action_link) unless action_link.nil?
|
136
|
+
end
|
137
|
+
end
|
138
|
+
|
139
|
+
def link_for_association(column, options = {})
|
140
|
+
begin
|
141
|
+
controller = column.polymorphic_association? ? :polymorph : active_scaffold_controller_for(column.association.klass)
|
142
|
+
rescue ActiveScaffold::ControllerNotFound
|
143
|
+
controller = nil
|
144
|
+
end
|
145
|
+
|
146
|
+
unless controller.nil?
|
147
|
+
options.reverse_merge! :label => column.label, :position => :after, :type => :member, :controller => (controller == :polymorph ? controller : controller.controller_path), :column => column
|
148
|
+
options[:parameters] ||= {}
|
149
|
+
options[:parameters].reverse_merge! :parent_model => column.active_record_class.to_s.underscore, :association => column.association.name
|
150
|
+
if column.plural_association?
|
151
|
+
# note: we can't create nested scaffolds on :through associations because there's no reverse association.
|
152
|
+
|
153
|
+
ActiveScaffold::DataStructures::ActionLink.new('index', options) #unless column.through_association?
|
154
|
+
else
|
155
|
+
actions = [:create, :update, :show]
|
156
|
+
actions = controller.active_scaffold_config.actions unless controller == :polymorph
|
157
|
+
column.actions_for_association_links.delete :new unless actions.include? :create
|
158
|
+
column.actions_for_association_links.delete :edit unless actions.include? :update
|
159
|
+
column.actions_for_association_links.delete :show unless actions.include? :show
|
160
|
+
ActiveScaffold::DataStructures::ActionLink.new(:none, options.merge({:crud_type => nil, :html_options => {:class => column.name}}))
|
161
|
+
end
|
162
|
+
end
|
163
|
+
end
|
164
|
+
|
165
|
+
def link_for_association_as_scope(scope, options = {})
|
166
|
+
options.reverse_merge! :label => scope, :position => :after, :type => :member, :controller => controller_path
|
167
|
+
options[:parameters] ||= {}
|
168
|
+
options[:parameters].reverse_merge! :parent_model => active_scaffold_config.model.to_s.underscore, :named_scope => scope
|
169
|
+
ActiveScaffold::DataStructures::ActionLink.new('index', options)
|
170
|
+
end
|
171
|
+
|
172
|
+
def add_active_scaffold_path(path)
|
173
|
+
@active_scaffold_paths = nil # Force active_scaffold_paths to rebuild
|
174
|
+
@active_scaffold_custom_paths << path
|
175
|
+
end
|
176
|
+
|
177
|
+
def add_active_scaffold_override_path(path)
|
178
|
+
@active_scaffold_paths = nil # Force active_scaffold_paths to rebuild
|
179
|
+
@active_scaffold_overrides.unshift path
|
180
|
+
end
|
181
|
+
|
182
|
+
def active_scaffold_paths
|
183
|
+
return @active_scaffold_paths unless @active_scaffold_paths.nil?
|
184
|
+
|
185
|
+
#@active_scaffold_paths = ActionView::PathSet.new
|
186
|
+
@active_scaffold_paths = []
|
187
|
+
@active_scaffold_paths.concat @active_scaffold_overrides unless @active_scaffold_overrides.nil?
|
188
|
+
@active_scaffold_paths.concat @active_scaffold_custom_paths unless @active_scaffold_custom_paths.nil?
|
189
|
+
@active_scaffold_paths.concat @active_scaffold_frontends unless @active_scaffold_frontends.nil?
|
190
|
+
@active_scaffold_paths
|
191
|
+
end
|
192
|
+
|
193
|
+
def active_scaffold_config
|
194
|
+
if @active_scaffold_config.nil?
|
195
|
+
self.superclass.active_scaffold_config if self.superclass.respond_to? :active_scaffold_config
|
196
|
+
else
|
197
|
+
@active_scaffold_config
|
198
|
+
end
|
199
|
+
end
|
200
|
+
|
201
|
+
def active_scaffold_config_block
|
202
|
+
@active_scaffold_config_block
|
203
|
+
end
|
204
|
+
|
205
|
+
def active_scaffold_superclasses_blocks
|
206
|
+
blocks = []
|
207
|
+
klass = self.superclass
|
208
|
+
while klass.respond_to? :active_scaffold_superclasses_blocks
|
209
|
+
blocks << klass.active_scaffold_config_block
|
210
|
+
klass = klass.superclass
|
211
|
+
end
|
212
|
+
blocks.compact.reverse
|
213
|
+
end
|
214
|
+
|
215
|
+
def active_scaffold_config_for(klass)
|
216
|
+
begin
|
217
|
+
controller = active_scaffold_controller_for(klass)
|
218
|
+
rescue ActiveScaffold::ControllerNotFound
|
219
|
+
config = ActiveScaffold::Config::Core.new(klass)
|
220
|
+
config._load_action_columns
|
221
|
+
config
|
222
|
+
else
|
223
|
+
controller.active_scaffold_config
|
224
|
+
end
|
225
|
+
end
|
226
|
+
|
227
|
+
# Tries to find a controller for the given ActiveRecord model.
|
228
|
+
# Searches in the namespace of the current controller for singular and plural versions of the conventional "#{model}Controller" syntax.
|
229
|
+
# You may override this method to customize the search routine.
|
230
|
+
def active_scaffold_controller_for(klass)
|
231
|
+
controller_namespace = self.to_s.split('::')[0...-1].join('::') + '::'
|
232
|
+
error_message = []
|
233
|
+
[controller_namespace, ''].each do |namespace|
|
234
|
+
["#{klass.to_s.underscore.pluralize}", "#{klass.to_s.underscore.pluralize.singularize}"].each do |controller_name|
|
235
|
+
begin
|
236
|
+
controller = "#{namespace}#{controller_name.camelize}Controller".constantize
|
237
|
+
rescue NameError => error
|
238
|
+
# Only rescue NameError associated with the controller constant not existing - not other compile errors
|
239
|
+
if error.message["uninitialized constant #{controller}"]
|
240
|
+
error_message << "#{namespace}#{controller_name.camelize}Controller"
|
241
|
+
next
|
242
|
+
else
|
243
|
+
raise
|
244
|
+
end
|
245
|
+
end
|
246
|
+
raise ActiveScaffold::ControllerNotFound, "#{controller} missing ActiveScaffold", caller unless controller.uses_active_scaffold?
|
247
|
+
raise ActiveScaffold::ControllerNotFound, "ActiveScaffold on #{controller} is not for #{klass} model.", caller unless controller.active_scaffold_config.model == klass
|
248
|
+
return controller
|
249
|
+
end
|
250
|
+
end
|
251
|
+
raise ActiveScaffold::ControllerNotFound, "Could not find " + error_message.join(" or "), caller
|
252
|
+
end
|
253
|
+
|
254
|
+
def uses_active_scaffold?
|
255
|
+
!active_scaffold_config.nil?
|
256
|
+
end
|
257
|
+
end
|
258
|
+
end
|
259
|
+
|
260
|
+
##
|
261
|
+
## Initialize the environment
|
262
|
+
##
|
263
|
+
unless Rails::VERSION::MAJOR == 3 && Rails::VERSION::MINOR >= 0
|
264
|
+
raise "This version of ActiveScaffold requires Rails 3.0 or higher. Please use an earlier version."
|
265
|
+
end
|
266
|
+
|
267
|
+
require File.dirname(__FILE__) + '/../environment'
|
268
|
+
|
269
|
+
##
|
270
|
+
## Run the install assets script, too, just to make sure
|
271
|
+
## But at least rescue the action in production
|
272
|
+
##
|
273
|
+
Rails::Application.initializer("active_scaffold_install_assets") do
|
274
|
+
begin
|
275
|
+
require File.dirname(__FILE__) + '/../install_assets'
|
276
|
+
rescue
|
277
|
+
raise $! unless Rails.env == 'production'
|
278
|
+
end
|
279
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
module ActiveScaffold::Actions
|
2
|
+
module CommonSearch
|
3
|
+
protected
|
4
|
+
def store_search_params_into_session
|
5
|
+
active_scaffold_session_storage[:search] = params.delete :search if params[:search]
|
6
|
+
end
|
7
|
+
|
8
|
+
def search_params
|
9
|
+
active_scaffold_session_storage[:search]
|
10
|
+
end
|
11
|
+
|
12
|
+
def search_ignore?
|
13
|
+
active_scaffold_config.list.always_show_search
|
14
|
+
end
|
15
|
+
|
16
|
+
# The default security delegates to ActiveRecordPermissions.
|
17
|
+
# You may override the method to customize.
|
18
|
+
def search_authorized?
|
19
|
+
authorized_for?(:crud_type => :read)
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
@@ -0,0 +1,150 @@
|
|
1
|
+
module ActiveScaffold::Actions
|
2
|
+
module Core
|
3
|
+
def self.included(base)
|
4
|
+
base.class_eval do
|
5
|
+
after_filter :clear_flashes
|
6
|
+
end
|
7
|
+
base.helper_method :nested?
|
8
|
+
base.helper_method :beginning_of_chain
|
9
|
+
end
|
10
|
+
def render_field
|
11
|
+
@record ||= if params[:in_place_editing]
|
12
|
+
active_scaffold_config.model.find params[:id]
|
13
|
+
else
|
14
|
+
active_scaffold_config.model.new
|
15
|
+
end
|
16
|
+
column = active_scaffold_config.columns[params[:column]]
|
17
|
+
if params[:in_place_editing]
|
18
|
+
render :inline => "<%= active_scaffold_input_for(active_scaffold_config.columns[params[:update_column].to_sym]) %>"
|
19
|
+
elsif !column.nil?
|
20
|
+
value = column_value_from_param_value(@record, column, params[:value])
|
21
|
+
@record.send "#{column.name}=", value
|
22
|
+
after_render_field(@record, column)
|
23
|
+
render :partial => "render_field", :collection => Array(params[:update_columns]), :content_type => 'text/javascript'
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
protected
|
28
|
+
|
29
|
+
def nested?
|
30
|
+
false
|
31
|
+
end
|
32
|
+
|
33
|
+
# override this method if you want to do something after render_field
|
34
|
+
def after_render_field(record, column); end
|
35
|
+
|
36
|
+
def authorized_for?(options = {})
|
37
|
+
active_scaffold_config.model.authorized_for?(options)
|
38
|
+
end
|
39
|
+
|
40
|
+
def clear_flashes
|
41
|
+
if request.xhr?
|
42
|
+
flash.keys.each do |flash_key|
|
43
|
+
flash[flash_key] = nil
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
def default_formats
|
49
|
+
[:html, :js, :json, :xml, :yaml]
|
50
|
+
end
|
51
|
+
# Returns true if the client accepts one of the MIME types passed to it
|
52
|
+
# ex: accepts? :html, :xml
|
53
|
+
def accepts?(*types)
|
54
|
+
for priority in request.accepts.compact
|
55
|
+
if priority == Mime::ALL
|
56
|
+
# Because IE always sends */* in the accepts header and we assume
|
57
|
+
# that if you really wanted XML or something else you would say so
|
58
|
+
# explicitly, we will assume */* to only ask for :html
|
59
|
+
return types.include?(:html)
|
60
|
+
elsif types.include?(priority.to_sym)
|
61
|
+
return true
|
62
|
+
end
|
63
|
+
end
|
64
|
+
false
|
65
|
+
end
|
66
|
+
|
67
|
+
def response_status
|
68
|
+
if successful?
|
69
|
+
action_name == 'create' ? 201 : 200
|
70
|
+
else
|
71
|
+
422
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
75
|
+
# API response object that will be converted to XML/YAML/JSON using to_xxx
|
76
|
+
def response_object
|
77
|
+
@response_object = successful? ? (@record || @records) : @record.errors
|
78
|
+
end
|
79
|
+
|
80
|
+
# Success is the existence of certain variables and the absence of errors (when applicable).
|
81
|
+
# Success can also be defined.
|
82
|
+
def successful?
|
83
|
+
if @successful.nil?
|
84
|
+
@records or (@record and @record.errors.count == 0 and @record.no_errors_in_associated?)
|
85
|
+
else
|
86
|
+
@successful
|
87
|
+
end
|
88
|
+
end
|
89
|
+
|
90
|
+
def successful=(val)
|
91
|
+
@successful = (val) ? true : false
|
92
|
+
end
|
93
|
+
|
94
|
+
# Redirect to the main page (override if the ActiveScaffold is used as a component on another controllers page) for Javascript degradation
|
95
|
+
def return_to_main
|
96
|
+
redirect_to main_path_to_return
|
97
|
+
end
|
98
|
+
|
99
|
+
# Override this method on your controller to define conditions to be used when querying a recordset (e.g. for List). The return of this method should be any format compatible with the :conditions clause of ActiveRecord::Base's find.
|
100
|
+
def conditions_for_collection
|
101
|
+
end
|
102
|
+
|
103
|
+
# Override this method on your controller to define joins to be used when querying a recordset (e.g. for List). The return of this method should be any format compatible with the :joins clause of ActiveRecord::Base's find.
|
104
|
+
def joins_for_collection
|
105
|
+
end
|
106
|
+
|
107
|
+
# Override this method on your controller to provide custom finder options to the find() call. The return of this method should be a hash.
|
108
|
+
def custom_finder_options
|
109
|
+
{}
|
110
|
+
end
|
111
|
+
|
112
|
+
#Overide this method on your controller to provide model with named scopes
|
113
|
+
def beginning_of_chain
|
114
|
+
active_scaffold_config.model
|
115
|
+
end
|
116
|
+
|
117
|
+
# Builds search conditions by search params for column names. This allows urls like "contacts/list?company_id=5".
|
118
|
+
def conditions_from_params
|
119
|
+
conditions = nil
|
120
|
+
params.reject {|key, value| [:controller, :action, :id, :page, :sort, :sort_direction].include?(key.to_sym)}.each do |key, value|
|
121
|
+
next unless active_scaffold_config.model.column_names.include?(key)
|
122
|
+
if value.is_a?(Array)
|
123
|
+
conditions = merge_conditions(conditions, ["#{active_scaffold_config.model.table_name}.#{key.to_s} in (?)", value])
|
124
|
+
else
|
125
|
+
conditions = merge_conditions(conditions, ["#{active_scaffold_config.model.table_name}.#{key.to_s} = ?", value])
|
126
|
+
end
|
127
|
+
end
|
128
|
+
conditions
|
129
|
+
end
|
130
|
+
private
|
131
|
+
def respond_to_action(action)
|
132
|
+
respond_to do |type|
|
133
|
+
send("#{action}_formats").each do |format|
|
134
|
+
type.send(format){ send("#{action}_respond_to_#{format}") }
|
135
|
+
end
|
136
|
+
end
|
137
|
+
end
|
138
|
+
|
139
|
+
def response_code_for_rescue(exception)
|
140
|
+
case exception
|
141
|
+
when ActiveScaffold::RecordNotAllowed
|
142
|
+
"403 Record Not Allowed"
|
143
|
+
when ActiveScaffold::ActionNotAllowed
|
144
|
+
"403 Action Not Allowed"
|
145
|
+
else
|
146
|
+
super
|
147
|
+
end
|
148
|
+
end
|
149
|
+
end
|
150
|
+
end
|