dbdoc_engine 0.1.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 +7 -0
- data/README.md +331 -0
- data/Rakefile +8 -0
- data/app/assets/builds/dbdoc_engine/application.css +5 -0
- data/app/assets/images/dbdoc_engine/arrowdown.svg +3 -0
- data/app/assets/images/dbdoc_engine/arrowhorizontal.svg +3 -0
- data/app/assets/images/dbdoc_engine/arrowleft.svg +3 -0
- data/app/assets/images/dbdoc_engine/changelog.svg +3 -0
- data/app/assets/images/dbdoc_engine/column_stats_dbdocs.svg +23 -0
- data/app/assets/images/dbdoc_engine/diagram.svg +3 -0
- data/app/assets/images/dbdoc_engine/double_arrow.svg +4 -0
- data/app/assets/images/dbdoc_engine/group_bu.svg +3 -0
- data/app/assets/images/dbdoc_engine/japan_circle.png +0 -0
- data/app/assets/images/dbdoc_engine/log_in_image.png +0 -0
- data/app/assets/images/dbdoc_engine/logo.svg +12 -0
- data/app/assets/images/dbdoc_engine/orange_changelog.svg +3 -0
- data/app/assets/images/dbdoc_engine/orange_fields.svg +23 -0
- data/app/assets/images/dbdoc_engine/orange_logo.svg +12 -0
- data/app/assets/images/dbdoc_engine/orange_table.svg +21 -0
- data/app/assets/images/dbdoc_engine/orange_updates.svg +43 -0
- data/app/assets/images/dbdoc_engine/orange_wiki.svg +3 -0
- data/app/assets/images/dbdoc_engine/search.svg +3 -0
- data/app/assets/images/dbdoc_engine/setting.svg +3 -0
- data/app/assets/images/dbdoc_engine/table_dbdocs.svg +21 -0
- data/app/assets/images/dbdoc_engine/uk_circle_transparent.png +0 -0
- data/app/assets/images/dbdoc_engine/update_stats_dbdocs.svg +43 -0
- data/app/assets/images/dbdoc_engine/wiki.svg +3 -0
- data/app/assets/stylesheets/dbdoc_engine/admin.css +176 -0
- data/app/assets/stylesheets/dbdoc_engine/admin_header.css +179 -0
- data/app/assets/stylesheets/dbdoc_engine/application.scss +1 -0
- data/app/assets/stylesheets/dbdoc_engine/changelog.css +173 -0
- data/app/assets/stylesheets/dbdoc_engine/dashboard.css +513 -0
- data/app/assets/stylesheets/dbdoc_engine/dbdoc_application.css +117 -0
- data/app/assets/stylesheets/dbdoc_engine/ecommerce.css +253 -0
- data/app/assets/stylesheets/dbdoc_engine/group_details.css +178 -0
- data/app/assets/stylesheets/dbdoc_engine/header.css +212 -0
- data/app/assets/stylesheets/dbdoc_engine/loading_spinner.css +127 -0
- data/app/assets/stylesheets/dbdoc_engine/login.css +213 -0
- data/app/assets/stylesheets/dbdoc_engine/schema_diagram.css +149 -0
- data/app/assets/stylesheets/dbdoc_engine/sidebar.css +296 -0
- data/app/assets/stylesheets/dbdoc_engine/table_details.css +417 -0
- data/app/controllers/dbdoc_engine/admin/base_controller.rb +23 -0
- data/app/controllers/dbdoc_engine/admin/dashboard_controller.rb +16 -0
- data/app/controllers/dbdoc_engine/admin/data_transfer_controller.rb +63 -0
- data/app/controllers/dbdoc_engine/admin/db_design_dynamic_tables_controller.rb +198 -0
- data/app/controllers/dbdoc_engine/admin/db_design_table_groups_controller.rb +107 -0
- data/app/controllers/dbdoc_engine/application_controller.rb +65 -0
- data/app/controllers/dbdoc_engine/concerns/internationalization.rb +57 -0
- data/app/controllers/dbdoc_engine/db_doc_sessions_controller.rb +33 -0
- data/app/controllers/dbdoc_engine/home_controller.rb +79 -0
- data/app/controllers/dbdoc_engine/schema_diagram_controller.rb +293 -0
- data/app/helper/dbdoc_engine/application_helper.rb +35 -0
- data/app/helpers/dbdoc_engine/application_helper.rb +4 -0
- data/app/helpers/dbdoc_engine/changelogs_helper.rb +27 -0
- data/app/helpers/dbdoc_engine/column_helper.rb +30 -0
- data/app/helpers/dbdoc_engine/db_design_dynamic_tables_helper.rb +15 -0
- data/app/helpers/dbdoc_engine/home_helper.rb +75 -0
- data/app/javascript/dbdoc_engine/application.js +12 -0
- data/app/javascript/dbdoc_engine/controllers/application.js +29 -0
- data/app/javascript/dbdoc_engine/controllers/auto_submit_controller.js +17 -0
- data/app/javascript/dbdoc_engine/controllers/chart_controller.js +58 -0
- data/app/javascript/dbdoc_engine/controllers/column-type_controller.js +149 -0
- data/app/javascript/dbdoc_engine/controllers/column_controller.js +362 -0
- data/app/javascript/dbdoc_engine/controllers/column_search_controller.js +42 -0
- data/app/javascript/dbdoc_engine/controllers/dbdoc_accordion_controller.js +42 -0
- data/app/javascript/dbdoc_engine/controllers/ecommerce_controller.js +73 -0
- data/app/javascript/dbdoc_engine/controllers/group_details_controller.js +88 -0
- data/app/javascript/dbdoc_engine/controllers/import_export_controller.js +200 -0
- data/app/javascript/dbdoc_engine/controllers/index.js +9 -0
- data/app/javascript/dbdoc_engine/controllers/language_controller.js +100 -0
- data/app/javascript/dbdoc_engine/controllers/loading_spinner_controller.js +48 -0
- data/app/javascript/dbdoc_engine/controllers/login_controller.js +75 -0
- data/app/javascript/dbdoc_engine/controllers/notification_controller.js +15 -0
- data/app/javascript/dbdoc_engine/controllers/schema_diagram_controller.js +1129 -0
- data/app/javascript/dbdoc_engine/controllers/select2_controller.js +67 -0
- data/app/javascript/dbdoc_engine/controllers/sidebar_controller.js +943 -0
- data/app/javascript/dbdoc_engine/controllers/table_details_controller.js +245 -0
- data/app/javascript/dbdoc_engine/controllers/table_group_validation_controller.js +148 -0
- data/app/javascript/dbdoc_engine/controllers/table_validation_controller.js +423 -0
- data/app/jobs/dbdoc_engine/application_job.rb +4 -0
- data/app/mailers/dbdoc_engine/application_mailer.rb +6 -0
- data/app/models/dbdoc_engine/application_record.rb +6 -0
- data/app/models/dbdoc_engine/concerns/soft_deletable.rb +30 -0
- data/app/models/dbdoc_engine/db_design_changelog.rb +44 -0
- data/app/models/dbdoc_engine/db_design_dynamic_column.rb +211 -0
- data/app/models/dbdoc_engine/db_design_dynamic_table.rb +124 -0
- data/app/models/dbdoc_engine/db_design_table_group.rb +88 -0
- data/app/models/dbdoc_engine/user.rb +21 -0
- data/app/queries/dbdoc_engine/admin_dashboard_queries.rb +71 -0
- data/app/queries/dbdoc_engine/db_design_changelog_queries.rb +68 -0
- data/app/queries/dbdoc_engine/db_design_dynamic_column_queries.rb +37 -0
- data/app/queries/dbdoc_engine/db_design_dynamic_table_commands.rb +106 -0
- data/app/queries/dbdoc_engine/db_design_dynamic_table_queries.rb +194 -0
- data/app/queries/dbdoc_engine/db_design_table_group_queries.rb +154 -0
- data/app/services/dbdoc_engine/db_design_dynamic_table_export_service.rb +38 -0
- data/app/services/dbdoc_engine/db_design_dynamic_table_handler_service.rb +49 -0
- data/app/services/dbdoc_engine/db_design_dynamic_tables_service.rb +21 -0
- data/app/services/dbdoc_engine/error_handler_service.rb +43 -0
- data/app/services/dbdoc_engine/schema_rb_import_service.rb +194 -0
- data/app/services/dbdoc_engine/schema_rb_parser_service.rb +339 -0
- data/app/services/dbdoc_engine/table_filter_service.rb +35 -0
- data/app/services/dbdoc_engine/table_groups_service.rb +199 -0
- data/app/services/dbdoc_engine/table_management_service.rb +192 -0
- data/app/views/dbdoc_engine/admin/dashboard/_action_badge.html.erb +11 -0
- data/app/views/dbdoc_engine/admin/dashboard/_changelog_rows.html.erb +22 -0
- data/app/views/dbdoc_engine/admin/dashboard/_changelog_table_headers.html.erb +8 -0
- data/app/views/dbdoc_engine/admin/dashboard/_filter_fields.html.erb +43 -0
- data/app/views/dbdoc_engine/admin/dashboard/index.html.erb +159 -0
- data/app/views/dbdoc_engine/admin/db_design_dynamic_tables/_column_fields.html.erb +225 -0
- data/app/views/dbdoc_engine/admin/db_design_dynamic_tables/_deleted_table_index.html.erb +110 -0
- data/app/views/dbdoc_engine/admin/db_design_dynamic_tables/_foreign_key_fields.html.erb +51 -0
- data/app/views/dbdoc_engine/admin/db_design_dynamic_tables/_form.html.erb +75 -0
- data/app/views/dbdoc_engine/admin/db_design_dynamic_tables/_recent_activity.html.erb +39 -0
- data/app/views/dbdoc_engine/admin/db_design_dynamic_tables/_table_columns.html.erb +127 -0
- data/app/views/dbdoc_engine/admin/db_design_dynamic_tables/_table_index.html.erb +109 -0
- data/app/views/dbdoc_engine/admin/db_design_dynamic_tables/_table_information.html.erb +99 -0
- data/app/views/dbdoc_engine/admin/db_design_dynamic_tables/deleted_tables.html.erb +95 -0
- data/app/views/dbdoc_engine/admin/db_design_dynamic_tables/edit.html.erb +23 -0
- data/app/views/dbdoc_engine/admin/db_design_dynamic_tables/export_all_to_excel.xlsx.axlsx +240 -0
- data/app/views/dbdoc_engine/admin/db_design_dynamic_tables/export_to_excel.xlsx.axlsx +135 -0
- data/app/views/dbdoc_engine/admin/db_design_dynamic_tables/index.html.erb +109 -0
- data/app/views/dbdoc_engine/admin/db_design_dynamic_tables/new.html.erb +25 -0
- data/app/views/dbdoc_engine/admin/db_design_dynamic_tables/show_table_info.html.erb +125 -0
- data/app/views/dbdoc_engine/admin/db_design_table_groups/_deleted_table_groups_list.html.erb +75 -0
- data/app/views/dbdoc_engine/admin/db_design_table_groups/_form.html.erb +88 -0
- data/app/views/dbdoc_engine/admin/db_design_table_groups/_table_groups_list.html.erb +82 -0
- data/app/views/dbdoc_engine/admin/db_design_table_groups/deleted_groups.html.erb +60 -0
- data/app/views/dbdoc_engine/admin/db_design_table_groups/edit.html.erb +25 -0
- data/app/views/dbdoc_engine/admin/db_design_table_groups/index.html.erb +85 -0
- data/app/views/dbdoc_engine/admin/db_design_table_groups/new.html.erb +26 -0
- data/app/views/dbdoc_engine/db_doc_sessions/new.html.erb +59 -0
- data/app/views/dbdoc_engine/home/changelog_details.html.erb +80 -0
- data/app/views/dbdoc_engine/home/changelogs.html.erb +20 -0
- data/app/views/dbdoc_engine/home/group_details.html.erb +94 -0
- data/app/views/dbdoc_engine/home/index.html.erb +11 -0
- data/app/views/dbdoc_engine/home/partials/_action_badge.html.erb +11 -0
- data/app/views/dbdoc_engine/home/partials/_breadcrumb_navigation.html.erb +30 -0
- data/app/views/dbdoc_engine/home/partials/_changelog_rows.html.erb +35 -0
- data/app/views/dbdoc_engine/home/partials/_changelog_table_headers.html.erb +16 -0
- data/app/views/dbdoc_engine/home/partials/_column_headers.html.erb +23 -0
- data/app/views/dbdoc_engine/home/partials/_column_row.html.erb +157 -0
- data/app/views/dbdoc_engine/home/partials/_filter_form.html.erb +47 -0
- data/app/views/dbdoc_engine/home/partials/_group_section.html.erb +84 -0
- data/app/views/dbdoc_engine/home/partials/_pagination.html.erb +5 -0
- data/app/views/dbdoc_engine/home/partials/_stats_container.html.erb +46 -0
- data/app/views/dbdoc_engine/home/partials/_table_groups.html.erb +7 -0
- data/app/views/dbdoc_engine/home/partials/_table_information_section.html.erb +50 -0
- data/app/views/dbdoc_engine/home/partials/_table_section.html.erb +48 -0
- data/app/views/dbdoc_engine/home/table_details.html.erb +9 -0
- data/app/views/dbdoc_engine/schema_diagram/index.html.erb +102 -0
- data/app/views/dbdoc_engine/shared/_admin_header.html.erb +78 -0
- data/app/views/dbdoc_engine/shared/_header.html.erb +94 -0
- data/app/views/dbdoc_engine/shared/_js_translations.html.erb +3 -0
- data/app/views/dbdoc_engine/shared/_language_button.html.erb +14 -0
- data/app/views/dbdoc_engine/shared/_sidebar.html.erb +128 -0
- data/app/views/kaminari/dbdoc_engine/_first_page.html.erb +3 -0
- data/app/views/kaminari/dbdoc_engine/_gap.html.erb +3 -0
- data/app/views/kaminari/dbdoc_engine/_last_page.html.erb +3 -0
- data/app/views/kaminari/dbdoc_engine/_next_page.html.erb +3 -0
- data/app/views/kaminari/dbdoc_engine/_page.html.erb +9 -0
- data/app/views/kaminari/dbdoc_engine/_paginator.html.erb +17 -0
- data/app/views/kaminari/dbdoc_engine/_prev_page.html.erb +3 -0
- data/app/views/layouts/dbdoc_engine/application.html.erb +107 -0
- data/app/views/layouts/dbdoc_engine/header.html.erb +108 -0
- data/config/importmap.rb +11 -0
- data/config/locales/en.yml +307 -0
- data/config/locales/ja.yml +306 -0
- data/config/routes.rb +73 -0
- data/db/migrate/rails7/20250227060610_create_db_design_table_groups.rb +15 -0
- data/db/migrate/rails7/20250227094626_create_db_design_dynamic_tables.rb +19 -0
- data/db/migrate/rails7/20250228022732_create_db_design_dynamic_columns.rb +34 -0
- data/db/migrate/rails7/20250401051453_create_db_design_changelogs.rb +26 -0
- data/db/migrate/rails7/20250411040822_create_users.rb +14 -0
- data/db/migrate/rails7/20250421080851_add_missing_indexes_to_dbdoc_tables.rb +23 -0
- data/db/migrate/rails8/20250227060610_create_db_design_table_groups.rb +15 -0
- data/db/migrate/rails8/20250227094626_create_db_design_dynamic_tables.rb +19 -0
- data/db/migrate/rails8/20250228022732_create_db_design_dynamic_columns.rb +34 -0
- data/db/migrate/rails8/20250401051453_create_db_design_changelogs.rb +26 -0
- data/db/migrate/rails8/20250411040822_create_users.rb +14 -0
- data/db/migrate/rails8/20250421080851_add_missing_indexes_to_dbdoc_tables.rb +23 -0
- data/db/seeds.rb +28 -0
- data/lib/dbdoc_engine/engine.rb +57 -0
- data/lib/dbdoc_engine/version.rb +3 -0
- data/lib/dbdoc_engine.rb +9 -0
- data/lib/generators/dbdoc_engine/install/install_generator.rb +245 -0
- data/lib/generators/dbdoc_engine/uninstall/uninstall_generator.rb +196 -0
- data/lib/tasks/dbdoc_engine_tasks.rake +44 -0
- data/public/dbdoc_engine_assets/images/camel_chess_head.png +0 -0
- data/public/dbdoc_engine_assets/images/dblogo.svg +4 -0
- data/public/dbdoc_engine_assets/images/japan_circle.png +0 -0
- data/public/dbdoc_engine_assets/images/king_chess_head.png +0 -0
- data/public/dbdoc_engine_assets/images/login-bg.svg +44 -0
- data/public/dbdoc_engine_assets/images/logo.png +0 -0
- data/public/dbdoc_engine_assets/images/logo.svg +12 -0
- data/public/dbdoc_engine_assets/images/queen_chess_head.png +0 -0
- data/public/dbdoc_engine_assets/images/soldier_chess_headd.png +0 -0
- data/public/dbdoc_engine_assets/images/uk_circle_transparent.png +0 -0
- metadata +415 -0
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
# queries/db_design_dynamic_table_commands.rb
|
|
2
|
+
|
|
3
|
+
# Service class for handling complex operations related to dynamic tables and their columns
|
|
4
|
+
# Uses transactions to ensure atomicity of operations
|
|
5
|
+
module DbdocEngine
|
|
6
|
+
class DbDesignDynamicTableCommands
|
|
7
|
+
class << self
|
|
8
|
+
# Creates a new dynamic table with associated columns in a transaction
|
|
9
|
+
# @param params [Hash] Table parameters including nested columns attributes
|
|
10
|
+
# @return [Hash] Result hash with :success status and either the table or errors
|
|
11
|
+
def create_with_columns(params)
|
|
12
|
+
table = DbDesignDynamicTable.new(params)
|
|
13
|
+
|
|
14
|
+
# Important: Validate the table OUTSIDE the transaction first
|
|
15
|
+
# This ensures uniqueness validations run before the transaction starts
|
|
16
|
+
unless table.valid?
|
|
17
|
+
return { success: false, errors: collect_errors(table) }
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
begin
|
|
21
|
+
# Wrap operations in transaction to ensure all-or-nothing behavior
|
|
22
|
+
ActiveRecord::Base.transaction do
|
|
23
|
+
# Now validate columns too
|
|
24
|
+
if valid_columns?(table)
|
|
25
|
+
table.save!
|
|
26
|
+
return { success: true, table: table }
|
|
27
|
+
end
|
|
28
|
+
# Rollback transaction if validations fail
|
|
29
|
+
raise ActiveRecord::Rollback
|
|
30
|
+
end
|
|
31
|
+
rescue ActiveRecord::RecordInvalid
|
|
32
|
+
# This would catch any exceptions if save! fails
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
# Return failure status with collected errors
|
|
36
|
+
{ success: false, errors: collect_errors(table) }
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
# Updates an existing dynamic table and its columns in a transaction
|
|
40
|
+
# @param table [DbDesignDynamicTable] Existing table to update
|
|
41
|
+
# @param params [Hash] New parameters including nested columns attributes
|
|
42
|
+
# @return [Hash] Result hash with :success status and either the table or errors
|
|
43
|
+
def update_with_columns(table, params)
|
|
44
|
+
table.assign_attributes(params)
|
|
45
|
+
|
|
46
|
+
# Validate table outside transaction first
|
|
47
|
+
unless table.valid?
|
|
48
|
+
return { success: false, errors: collect_errors(table) }
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
# Transaction block for atomic updates
|
|
52
|
+
ActiveRecord::Base.transaction do
|
|
53
|
+
# Now validate columns
|
|
54
|
+
if valid_columns?(table)
|
|
55
|
+
table.save!
|
|
56
|
+
return { success: true, table: table }
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
# Collect errors and rollback if validations fail
|
|
60
|
+
raise ActiveRecord::Rollback
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
# Return failure status with collected errors
|
|
64
|
+
{ success: false, errors: collect_errors(table) }
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
private
|
|
68
|
+
|
|
69
|
+
# Validates table attributes
|
|
70
|
+
# @param table [DbDesignDynamicTable] Table instance to validate
|
|
71
|
+
# @return [Boolean] Validation status
|
|
72
|
+
def valid_table?(table)
|
|
73
|
+
table.valid?
|
|
74
|
+
end
|
|
75
|
+
|
|
76
|
+
# Validates all associated columns
|
|
77
|
+
# @param table [DbDesignDynamicTable] Table instance with columns to validate
|
|
78
|
+
# @return [Boolean] Overall validation status of all columns
|
|
79
|
+
def valid_columns?(table)
|
|
80
|
+
table.db_design_dynamic_columns.all?(&:valid?)
|
|
81
|
+
end
|
|
82
|
+
|
|
83
|
+
# Aggregates validation errors from table and columns into a single hash
|
|
84
|
+
# @param table [DbDesignDynamicTable] Table instance with errors
|
|
85
|
+
# @return [Hash] Structured error messages with keys indicating error sources
|
|
86
|
+
def collect_errors(table)
|
|
87
|
+
errors = {}
|
|
88
|
+
|
|
89
|
+
# Collect table-level errors
|
|
90
|
+
table.errors.each do |error|
|
|
91
|
+
errors[error.attribute] = error.message
|
|
92
|
+
end
|
|
93
|
+
|
|
94
|
+
# Collect column errors with indexed keys to prevent overwrites
|
|
95
|
+
table.db_design_dynamic_columns.each_with_index do |col, idx|
|
|
96
|
+
col.errors.each do |error|
|
|
97
|
+
# Format: "column_0_columnname" for first column's name error
|
|
98
|
+
errors["column#{idx}_#{error.attribute}"] = error.message
|
|
99
|
+
end
|
|
100
|
+
end
|
|
101
|
+
|
|
102
|
+
errors
|
|
103
|
+
end
|
|
104
|
+
end
|
|
105
|
+
end
|
|
106
|
+
end
|
|
@@ -0,0 +1,194 @@
|
|
|
1
|
+
# queries/db_design_dynamic_table_queries.rb
|
|
2
|
+
|
|
3
|
+
# Query class handling database operations for dynamic tables and their relationships
|
|
4
|
+
module DbdocEngine
|
|
5
|
+
class DbDesignDynamicTableQueries
|
|
6
|
+
# Associations to eager load with table queries
|
|
7
|
+
INCLUDES_ASSOCIATIONS = %i[db_design_dynamic_columns db_design_table_group].freeze
|
|
8
|
+
|
|
9
|
+
class << self
|
|
10
|
+
# Centralized access to the DynamicTable model class
|
|
11
|
+
# @return [Class] DbDesignDynamicTable model class
|
|
12
|
+
def model
|
|
13
|
+
DbDesignDynamicTable
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
# Count tables belonging to a specific group
|
|
17
|
+
# @param group [DbDesignTableGroup] Group to count tables for
|
|
18
|
+
# @return [Integer] Number of tables in the group
|
|
19
|
+
def count_tables_in_group(group, include_deleted = false)
|
|
20
|
+
if include_deleted
|
|
21
|
+
group.db_design_dynamic_tables.with_deleted.size
|
|
22
|
+
else
|
|
23
|
+
group.db_design_dynamic_tables.size
|
|
24
|
+
end
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
# Find a table by ID with eager-loaded columns and group
|
|
28
|
+
# @param id [Integer] Table ID to find
|
|
29
|
+
# @return [DbDesignDynamicTable, nil] Found table or nil
|
|
30
|
+
def find_table_with_columns_and_group(id)
|
|
31
|
+
model.includes(INCLUDES_ASSOCIATIONS).find_by(id: id)
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
# Get all active tables with their columns and groups
|
|
35
|
+
# @return [ActiveRecord::Relation] Collection of tables with associations
|
|
36
|
+
def all_tables_with_columns_and_groups
|
|
37
|
+
model.includes(INCLUDES_ASSOCIATIONS)
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
# Ordered table groups with associated tables
|
|
41
|
+
def all_tables_ordered_by_group
|
|
42
|
+
model.includes(INCLUDES_ASSOCIATIONS)
|
|
43
|
+
.joins(:db_design_table_group)
|
|
44
|
+
.order(Arel.sql('LOWER(db_design_table_groups.group_name) ASC,
|
|
45
|
+
LOWER(db_design_dynamic_tables.table_name) ASC'))
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
# Get soft-deleted tables with their associations
|
|
49
|
+
# @return [ActiveRecord::Relation] Collection of deleted tables
|
|
50
|
+
def all_deleted_tables_with_columns_and_groups
|
|
51
|
+
model.with_deleted.only_deleted.includes(INCLUDES_ASSOCIATIONS)
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
# Count all active tables
|
|
55
|
+
# @return [Integer] Total active table count
|
|
56
|
+
def count_all_tables
|
|
57
|
+
model.count
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
# Count all soft-deleted tables
|
|
61
|
+
# @return [Integer] Total deleted table count
|
|
62
|
+
def count_all_deleted_tables
|
|
63
|
+
model.with_deleted.only_deleted.count
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
# Find table including soft-deleted records
|
|
67
|
+
# @param id [Integer] Table ID to find
|
|
68
|
+
# @return [DbDesignDynamicTable] Table with deleted records
|
|
69
|
+
def find_table_with_deleted(id)
|
|
70
|
+
model.with_deleted.find(id)
|
|
71
|
+
end
|
|
72
|
+
|
|
73
|
+
# Get all tables except specified ID
|
|
74
|
+
# @param id [Integer] Table ID to exclude
|
|
75
|
+
# @return [ActiveRecord::Relation] Tables excluding specified ID
|
|
76
|
+
def find_all_except(id)
|
|
77
|
+
model.where.not(id: id)
|
|
78
|
+
end
|
|
79
|
+
|
|
80
|
+
# Find table by its name
|
|
81
|
+
# @param table_name [String] Name to search for
|
|
82
|
+
# @return [DbDesignDynamicTable, nil] Matching table or nil
|
|
83
|
+
def find_by_table_name(table_name)
|
|
84
|
+
model.find_by(table_name: table_name)
|
|
85
|
+
end
|
|
86
|
+
|
|
87
|
+
# Check if a column is referenced as foreign key
|
|
88
|
+
# @param table_name [String] Source table name
|
|
89
|
+
# @param column_name [String] Column name to check
|
|
90
|
+
# @param only_active [Boolean] Only check active tables
|
|
91
|
+
# @return [Boolean] Reference existence status
|
|
92
|
+
def check_column_is_referenced(table_name, column_name, only_active: false)
|
|
93
|
+
query = DbDesignDynamicColumn.where(
|
|
94
|
+
foreign_table_name: table_name,
|
|
95
|
+
foreign_column_name: column_name
|
|
96
|
+
)
|
|
97
|
+
|
|
98
|
+
query = active_tables_scope(query) if only_active
|
|
99
|
+
query.exists?
|
|
100
|
+
end
|
|
101
|
+
|
|
102
|
+
# Get group name for a table group ID
|
|
103
|
+
# @param group_id [Integer] Group ID to lookup
|
|
104
|
+
# @return [String, nil] Group name or nil
|
|
105
|
+
def find_table_group_name(group_id)
|
|
106
|
+
DbDesignTableGroupQueries.find_group_name(group_id)
|
|
107
|
+
end
|
|
108
|
+
|
|
109
|
+
# Get table name by ID
|
|
110
|
+
# @param table_id [Integer] Table ID to lookup
|
|
111
|
+
# @return [String, nil] Table name or nil
|
|
112
|
+
def find_table_name(table_id)
|
|
113
|
+
model.find_by(id: table_id)&.table_name
|
|
114
|
+
end
|
|
115
|
+
|
|
116
|
+
# Check if group contains active/non-deleted tables
|
|
117
|
+
# @param group_id [Integer] Group ID to check
|
|
118
|
+
# @param include_deleted [Boolean] Include deleted tables in check
|
|
119
|
+
# @return [Boolean] Existence status
|
|
120
|
+
def group_has_active_tables?(group_id, include_deleted = false)
|
|
121
|
+
query = model.where(db_design_table_group_id: group_id)
|
|
122
|
+
query = include_deleted ? query.with_deleted : query.without_deleted
|
|
123
|
+
query.exists?
|
|
124
|
+
end
|
|
125
|
+
|
|
126
|
+
# Find table with eager-loaded group information
|
|
127
|
+
# @param id [Integer] Table ID to find
|
|
128
|
+
# @return [DbDesignDynamicTable] Table with group association
|
|
129
|
+
def find_table_with_group(id)
|
|
130
|
+
model.includes(:db_design_table_group).find(id)
|
|
131
|
+
end
|
|
132
|
+
|
|
133
|
+
# Filter relation by group ID
|
|
134
|
+
# @param relation [ActiveRecord::Relation] Base query to filter
|
|
135
|
+
# @param group_id [Integer] Group ID to filter by
|
|
136
|
+
# @return [ActiveRecord::Relation] Filtered query
|
|
137
|
+
def filter_by_group(relation, group_id)
|
|
138
|
+
relation.where(db_design_table_group_id: group_id)
|
|
139
|
+
end
|
|
140
|
+
|
|
141
|
+
# Search tables by name or group name
|
|
142
|
+
# @param relation [ActiveRecord::Relation] Base query to search
|
|
143
|
+
# @param search_term [String] Term to search for
|
|
144
|
+
# @return [ActiveRecord::Relation] Modified query with search filters
|
|
145
|
+
def search_tables(relation, search_term)
|
|
146
|
+
return relation if search_term.blank?
|
|
147
|
+
|
|
148
|
+
sanitized_term = "%#{search_term.downcase}%"
|
|
149
|
+
relation.left_joins(:db_design_table_group)
|
|
150
|
+
.where("LOWER(db_design_dynamic_tables.table_name) LIKE :term OR LOWER(db_design_table_groups.group_name) LIKE :term",
|
|
151
|
+
term: sanitized_term)
|
|
152
|
+
end
|
|
153
|
+
|
|
154
|
+
def active_tables_with_columns
|
|
155
|
+
model.where(deleted_at: nil)
|
|
156
|
+
.where(
|
|
157
|
+
"EXISTS (SELECT 1 FROM db_design_dynamic_columns " \
|
|
158
|
+
"WHERE db_design_dynamic_columns.db_design_dynamic_table_id = db_design_dynamic_tables.id)"
|
|
159
|
+
)
|
|
160
|
+
end
|
|
161
|
+
|
|
162
|
+
def table_exists?(table_name)
|
|
163
|
+
model.exists?(table_name: table_name, deleted_at: nil)
|
|
164
|
+
end
|
|
165
|
+
|
|
166
|
+
private
|
|
167
|
+
|
|
168
|
+
# Scope query to active tables only
|
|
169
|
+
# @param query [ActiveRecord::Relation] Query to modify
|
|
170
|
+
# @return [ActiveRecord::Relation] Scoped query
|
|
171
|
+
def active_tables_scope(query)
|
|
172
|
+
query.joins(:db_design_dynamic_table)
|
|
173
|
+
.where(db_design_dynamic_tables: { deleted_at: nil })
|
|
174
|
+
end
|
|
175
|
+
|
|
176
|
+
# Check for table references (private implementation)
|
|
177
|
+
# @param table_id [Integer] Table ID to check
|
|
178
|
+
# @return [Boolean] Reference existence status
|
|
179
|
+
def check_table_references(_table_id)
|
|
180
|
+
DbDesignDynamicColumn
|
|
181
|
+
.joins(:db_design_dynamic_table)
|
|
182
|
+
.where(foreign_table_name: table.table_name)
|
|
183
|
+
.exists?
|
|
184
|
+
end
|
|
185
|
+
|
|
186
|
+
# Find table with columns and group (private implementation)
|
|
187
|
+
# @param id [Integer] Table ID to find
|
|
188
|
+
# @return [DbDesignDynamicTable, nil] Found table or nil
|
|
189
|
+
def find_with_columns_and_group(id)
|
|
190
|
+
model.includes(INCLUDES_ASSOCIATIONS).find_by(id: id)
|
|
191
|
+
end
|
|
192
|
+
end
|
|
193
|
+
end
|
|
194
|
+
end
|
|
@@ -0,0 +1,154 @@
|
|
|
1
|
+
# queries/db_design_table_group_queries.rb
|
|
2
|
+
|
|
3
|
+
# Query class handling database operations for table groups and their associations
|
|
4
|
+
module DbdocEngine
|
|
5
|
+
class DbDesignTableGroupQueries
|
|
6
|
+
# Eager loading configuration for tables and columns associations
|
|
7
|
+
TABLE_INCLUDES = { db_design_dynamic_tables: :db_design_dynamic_columns }.freeze
|
|
8
|
+
|
|
9
|
+
class << self
|
|
10
|
+
# Centralized model reference for table groups
|
|
11
|
+
# @return [Class] DbDesignTableGroup model class
|
|
12
|
+
def model
|
|
13
|
+
DbDesignTableGroup
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
# Fetch all table groups with their associated tables and columns
|
|
17
|
+
# @return [ActiveRecord::Relation] Collection of groups with eager-loaded associations
|
|
18
|
+
def all_groups_with_tables_and_columns
|
|
19
|
+
model.includes(TABLE_INCLUDES).all
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
# Find a specific group by ID with preloaded tables and columns
|
|
23
|
+
# @param id [Integer] Group ID to find
|
|
24
|
+
# @return [DbDesignTableGroup, nil] Found group or nil
|
|
25
|
+
def find_group_with_tables_and_columns(id)
|
|
26
|
+
model.includes(TABLE_INCLUDES).find_by(id: id)
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
# Count all active (non-deleted) table groups
|
|
30
|
+
# @return [Integer] Total count of active groups
|
|
31
|
+
def count_all_groups
|
|
32
|
+
model.count
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
# Retrieve lightweight group data for selection lists
|
|
36
|
+
# @return [ActiveRecord::Relation] Collection of groups with only ID and name
|
|
37
|
+
def select_all_groups
|
|
38
|
+
model.select(:id, :group_name)
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
# Find a group including soft-deleted records
|
|
42
|
+
# @param id [Integer] Group ID to find
|
|
43
|
+
# @return [DbDesignTableGroup] Group including soft-deleted ones
|
|
44
|
+
def find_with_deleted(id)
|
|
45
|
+
model.with_deleted.find(id)
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
# Unified search across groups with optional deleted records
|
|
49
|
+
# @param search_term [String] Optional search string
|
|
50
|
+
# @param include_deleted [Boolean] Flag to include soft-deleted records
|
|
51
|
+
# @return [ActiveRecord::Relation] Filtered collection of groups
|
|
52
|
+
def search_all_groups(search_term = nil, include_deleted = false)
|
|
53
|
+
query = include_deleted ? model.with_deleted : model.all
|
|
54
|
+
query = apply_search_scope(query, search_term)
|
|
55
|
+
query.order(Arel.sql("LOWER(group_name) ASC")) # Add ordering here
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
# Search specifically in soft-deleted groups
|
|
59
|
+
# @param search_term [String] Optional search string
|
|
60
|
+
# @return [ActiveRecord::Relation] Filtered collection of deleted groups
|
|
61
|
+
def search_deleted_groups(search_term = nil)
|
|
62
|
+
apply_search_scope(model.only_deleted, search_term)
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
# Get group names excluding a specific entry
|
|
66
|
+
# @param excluded_id [Integer] ID to exclude from results
|
|
67
|
+
# @return [Array<String>] Array of group names
|
|
68
|
+
def group_names_except(excluded_id)
|
|
69
|
+
model.where.not(id: excluded_id).pluck(:group_name)
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
# Find group name by ID
|
|
73
|
+
# @param group_id [Integer] Group ID to lookup
|
|
74
|
+
# @return [String, nil] Group name or nil
|
|
75
|
+
def find_group_name(group_id)
|
|
76
|
+
model.find_by(id: group_id)&.group_name
|
|
77
|
+
end
|
|
78
|
+
|
|
79
|
+
# Check if a group name exists in active records
|
|
80
|
+
# @param group_name [String] Name to check for existence
|
|
81
|
+
# @return [Boolean] Existence status
|
|
82
|
+
def group_exists?(group_name)
|
|
83
|
+
model.without_deleted.where(group_name: group_name).exists?
|
|
84
|
+
end
|
|
85
|
+
|
|
86
|
+
# Create a new table group
|
|
87
|
+
# @param params [Hash] Group attributes
|
|
88
|
+
# @return [DbDesignTableGroup] New group instance (persisted if valid)
|
|
89
|
+
def create_table_group(params)
|
|
90
|
+
model.new(params).tap(&:save)
|
|
91
|
+
end
|
|
92
|
+
|
|
93
|
+
# Update existing table group
|
|
94
|
+
# @param table_group [DbDesignTableGroup] Group instance to update
|
|
95
|
+
# @param params [Hash] New attributes
|
|
96
|
+
# @return [Boolean] Update success status
|
|
97
|
+
def update_table_group(table_group, params)
|
|
98
|
+
table_group.update(params)
|
|
99
|
+
end
|
|
100
|
+
|
|
101
|
+
# Soft delete a table group
|
|
102
|
+
# @param table_group [DbDesignTableGroup] Group to mark as deleted
|
|
103
|
+
# @return [Boolean] Deletion success status
|
|
104
|
+
def soft_delete(table_group)
|
|
105
|
+
table_group.soft_delete
|
|
106
|
+
end
|
|
107
|
+
|
|
108
|
+
# Restore a soft-deleted group
|
|
109
|
+
# @param table_group [DbDesignTableGroup] Group to restore
|
|
110
|
+
# @return [Boolean] Restoration success status
|
|
111
|
+
def restore(table_group)
|
|
112
|
+
table_group.restore
|
|
113
|
+
end
|
|
114
|
+
|
|
115
|
+
# Permanently delete a group
|
|
116
|
+
# @param table_group [DbDesignTableGroup] Group to destroy
|
|
117
|
+
# @return [Boolean] Deletion success status
|
|
118
|
+
def permanent_delete(table_group)
|
|
119
|
+
table_group.destroy
|
|
120
|
+
end
|
|
121
|
+
|
|
122
|
+
# Get all groups for selection dropdowns
|
|
123
|
+
# @return [ActiveRecord::Relation] Ordered list of groups with ID and name
|
|
124
|
+
def all_groups_for_selection
|
|
125
|
+
model.select(:id, :group_name).order(:group_name)
|
|
126
|
+
end
|
|
127
|
+
|
|
128
|
+
# Find group with associated tables
|
|
129
|
+
# @param group_id [Integer] Group ID to find
|
|
130
|
+
# @return [DbDesignTableGroup] Group with associated tables
|
|
131
|
+
def find_group_with_tables(group_id)
|
|
132
|
+
model.includes(:db_design_dynamic_tables).find(group_id)
|
|
133
|
+
end
|
|
134
|
+
|
|
135
|
+
def groups_with_tables_having_columns
|
|
136
|
+
model.includes(db_design_dynamic_tables: :db_design_dynamic_columns)
|
|
137
|
+
.references(:db_design_dynamic_tables)
|
|
138
|
+
.where(db_design_dynamic_tables: { deleted_at: nil })
|
|
139
|
+
end
|
|
140
|
+
|
|
141
|
+
private
|
|
142
|
+
|
|
143
|
+
# Internal search scope handler
|
|
144
|
+
# @param query [ActiveRecord::Relation] Base query to modify
|
|
145
|
+
# @param search_term [String] Search string for filtering
|
|
146
|
+
# @return [ActiveRecord::Relation] Modified query with search filters
|
|
147
|
+
def apply_search_scope(query, search_term)
|
|
148
|
+
return query if search_term.blank?
|
|
149
|
+
|
|
150
|
+
query.where("group_name ILIKE ?", "%#{search_term.strip}%")
|
|
151
|
+
end
|
|
152
|
+
end
|
|
153
|
+
end
|
|
154
|
+
end
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
# app/services/db_design_dynamic_table_export_service.rb
|
|
2
|
+
module DbdocEngine
|
|
3
|
+
class DbDesignDynamicTableExportService
|
|
4
|
+
def initialize(params, controller)
|
|
5
|
+
@params = params # Parameters passed from the controller
|
|
6
|
+
@controller = controller # Reference to the controller instance
|
|
7
|
+
end
|
|
8
|
+
|
|
9
|
+
# Handles export of a single table to Excel
|
|
10
|
+
def export_single
|
|
11
|
+
table = DbdocEngine::DbDesignDynamicTableQueries.find_table_with_deleted(@params[:id]) # Find table by ID (including soft-deleted)
|
|
12
|
+
columns = table.db_design_dynamic_columns # Get all columns for the table
|
|
13
|
+
|
|
14
|
+
@controller.instance_variable_set(:@table, table) # Set instance variable for table
|
|
15
|
+
@controller.instance_variable_set(:@columns, columns) # Set instance variable for columns
|
|
16
|
+
|
|
17
|
+
@controller.respond_to do |format| # Prepare Excel response
|
|
18
|
+
format.xlsx do
|
|
19
|
+
filename = "#{table.table_name.parameterize}_details.xlsx" # Set download filename
|
|
20
|
+
@controller.response.headers["Content-Disposition"] = "attachment; filename=#{filename}"
|
|
21
|
+
end
|
|
22
|
+
end
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
# Handles export of all tables to Excel
|
|
26
|
+
def export_all
|
|
27
|
+
tables = DbdocEngine::DbDesignDynamicTableQueries.all_tables_with_columns_and_groups # Get all tables with columns and groups
|
|
28
|
+
@controller.instance_variable_set(:@tables, tables) # Set instance variable for use in view
|
|
29
|
+
|
|
30
|
+
@controller.respond_to do |format| # Prepare Excel response
|
|
31
|
+
format.xlsx do
|
|
32
|
+
filename = "all_tables_details_#{Date.today.strftime('%Y%m%d')}.xlsx" # Set download filename with today's date
|
|
33
|
+
@controller.response.headers["Content-Disposition"] = "attachment; filename=#{filename}"
|
|
34
|
+
end
|
|
35
|
+
end
|
|
36
|
+
end
|
|
37
|
+
end
|
|
38
|
+
end
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
# Handles create and update operations for DbDesignDynamicTable
|
|
2
|
+
module DbdocEngine
|
|
3
|
+
class DbDesignDynamicTableHandlerService
|
|
4
|
+
def initialize(controller_context, table_params, table = nil)
|
|
5
|
+
@controller = controller_context # Reference to the controller instance
|
|
6
|
+
@table_params = table_params # Table parameters from the controller
|
|
7
|
+
@table = table # Existing table object (optional, for update)
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
# Handles table creation operation
|
|
11
|
+
def create
|
|
12
|
+
result = service.create_table # Call service to create the table
|
|
13
|
+
|
|
14
|
+
if result[:success]
|
|
15
|
+
@controller.flash[:notice] = I18n.t("dbdoc.table_creation") # Success message
|
|
16
|
+
@controller.redirect_to @controller.admin_db_design_dynamic_tables_path # Redirect to the table list
|
|
17
|
+
else
|
|
18
|
+
handle_failure(result, :new) # Handle failure (render 'new' view)
|
|
19
|
+
end
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
# Handles table update operation
|
|
23
|
+
def update
|
|
24
|
+
result = service.update_table(@table) # Call service to update the table
|
|
25
|
+
|
|
26
|
+
if result[:success]
|
|
27
|
+
@controller.flash[:notice] = I18n.t("dbdoc.table_updation") # Success message
|
|
28
|
+
@controller.redirect_to @controller.admin_db_design_dynamic_tables_path # Redirect to the table list
|
|
29
|
+
else
|
|
30
|
+
handle_failure(result, :edit) # Handle failure (render 'edit' view)
|
|
31
|
+
end
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
private
|
|
35
|
+
|
|
36
|
+
# Initializes and caches the service object for table operations
|
|
37
|
+
def service
|
|
38
|
+
@service ||= DbDesignDynamicTablesService.new(@table_params) # Instantiate the service with table parameters
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
# Handles failure scenario (render the appropriate view with errors)
|
|
42
|
+
def handle_failure(result, render_view)
|
|
43
|
+
@controller.instance_variable_set(:@table, @table || DbDesignDynamicTable.new(@table_params)) # Set table instance
|
|
44
|
+
@controller.send(:load_other_tables) # Load other tables for reference in the view
|
|
45
|
+
@controller.send(:handle_errors, @controller.instance_variable_get(:@table), result) # Handle and display errors
|
|
46
|
+
@controller.render render_view, status: :unprocessable_entity # Render the appropriate view with errors
|
|
47
|
+
end
|
|
48
|
+
end
|
|
49
|
+
end
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
# Service for managing dynamic table creation and updates.
|
|
2
|
+
# This service handles the creation and updating of dynamic tables,
|
|
3
|
+
# including the validation of table and nested column data,
|
|
4
|
+
# and ensures that all changes are committed within a transaction.
|
|
5
|
+
module DbdocEngine
|
|
6
|
+
class DbDesignDynamicTablesService
|
|
7
|
+
def initialize(params)
|
|
8
|
+
@params = params
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
# Create new table.
|
|
12
|
+
def create_table
|
|
13
|
+
DbDesignDynamicTableCommands.create_with_columns(@params)
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
# Update existing table.
|
|
17
|
+
def update_table(table)
|
|
18
|
+
DbDesignDynamicTableCommands.update_with_columns(table, @params)
|
|
19
|
+
end
|
|
20
|
+
end
|
|
21
|
+
end
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
# Service for handling errors in table operations
|
|
2
|
+
module DbdocEngine
|
|
3
|
+
class ErrorHandlerService
|
|
4
|
+
attr_reader :table, :result, :table_params
|
|
5
|
+
|
|
6
|
+
def initialize(table, result, table_params = nil)
|
|
7
|
+
@table = table
|
|
8
|
+
@result = result
|
|
9
|
+
@table_params = table_params
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
# Process errors and add them to the appropriate objects
|
|
13
|
+
def process_errors
|
|
14
|
+
return unless result[:errors].present?
|
|
15
|
+
|
|
16
|
+
result[:errors].each do |attribute, messages|
|
|
17
|
+
if attribute.to_s.start_with?("db_design_dynamic_columns.")
|
|
18
|
+
handle_column_error(attribute, messages)
|
|
19
|
+
else
|
|
20
|
+
handle_table_error(attribute, messages)
|
|
21
|
+
end
|
|
22
|
+
end
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
private
|
|
26
|
+
|
|
27
|
+
# Handle errors for specific columns
|
|
28
|
+
def handle_column_error(attribute, messages)
|
|
29
|
+
match = attribute.to_s.match(/db_design_dynamic_columns\.(\d+)/)
|
|
30
|
+
return unless match
|
|
31
|
+
|
|
32
|
+
index = match[1].to_i
|
|
33
|
+
return unless table.db_design_dynamic_columns[index]
|
|
34
|
+
|
|
35
|
+
table.db_design_dynamic_columns[index].errors.add(:base, messages)
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
# Handle errors for the table itself
|
|
39
|
+
def handle_table_error(attribute, messages)
|
|
40
|
+
Array(messages).each { |message| table.errors.add(attribute, message) }
|
|
41
|
+
end
|
|
42
|
+
end
|
|
43
|
+
end
|