para 0.5.4 → 0.6.2
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/app/assets/javascripts/para/admin/async-progress.coffee +29 -0
- data/app/assets/javascripts/para/admin/filters-form.coffee +1 -1
- data/app/assets/javascripts/para/admin/importers.coffee +38 -0
- data/app/assets/javascripts/para/admin/table.coffee +1 -1
- data/app/assets/javascripts/para/admin/tabs.coffee +1 -1
- data/app/assets/javascripts/para/admin/theme_actions.coffee +1 -1
- data/app/assets/javascripts/para/admin/tree.coffee +5 -5
- data/app/assets/javascripts/para/admin.coffee +2 -1
- data/app/assets/javascripts/para/inputs/nested_many.coffee +1 -1
- data/app/assets/javascripts/para/lib/remote-file-forms.coffee +60 -0
- data/app/assets/javascripts/para/lib/turbolinks-loading.coffee +1 -1
- data/app/assets/javascripts/para/lib/turbolinks-reloader.coffee +19 -0
- data/app/assets/stylesheets/para/admin/src/datetimepicker.sass +3 -1
- data/app/assets/stylesheets/para/admin/src/fuelux.sass +4 -2
- data/app/assets/stylesheets/para/admin/src/nested_many.sass +5 -0
- data/app/assets/stylesheets/para/admin/src/redactor.sass +8 -5
- data/app/assets/stylesheets/para/admin/src/selectize.sass +7 -4
- data/app/assets/stylesheets/para/admin/theme/_breadcrumb.sass +20 -12
- data/app/assets/stylesheets/para/admin/theme/_buttons.sass +6 -2
- data/app/assets/stylesheets/para/admin/theme/_checkable.sass +4 -2
- data/app/assets/stylesheets/para/admin/theme/_commonds.sass +6 -3
- data/app/assets/stylesheets/para/admin/theme/_dropdown.sass +3 -1
- data/app/assets/stylesheets/para/admin/theme/_form.sass +4 -2
- data/app/assets/stylesheets/para/admin/theme/_list.sass +7 -5
- data/app/assets/stylesheets/para/admin/theme/_navigation.sass +12 -66
- data/app/assets/stylesheets/para/admin/theme/_navtabs.sass +18 -14
- data/app/assets/stylesheets/para/admin/theme/_orderable.sass +7 -3
- data/app/assets/stylesheets/para/admin/theme/_panel.sass +19 -13
- data/app/assets/stylesheets/para/admin/theme/_tree.sass +4 -2
- data/app/assets/stylesheets/para/overrides/theme.sass +14 -10
- data/app/controllers/para/admin/base_controller.rb +0 -5
- data/app/controllers/para/admin/crud_resources_controller.rb +5 -19
- data/app/controllers/para/admin/{singleton_resources_controller.rb → form_resources_controller.rb} +4 -4
- data/app/controllers/para/admin/imports_controller.rb +68 -0
- data/app/controllers/para/admin/resources_controller.rb +0 -1
- data/app/decorators/para/component/base_decorator.rb +6 -18
- data/app/decorators/para/component/crud_decorator.rb +3 -3
- data/app/decorators/para/component/{singleton_resource_decorator.rb → form_decorator.rb} +6 -6
- data/app/helpers/para/admin/components_helper.rb +12 -1
- data/app/helpers/para/admin/decorators_helper.rb +13 -0
- data/app/helpers/para/markup_helper.rb +4 -0
- data/app/helpers/para/search_helper.rb +1 -4
- data/app/models/para/component/base.rb +17 -14
- data/app/models/para/component/crud.rb +17 -0
- data/app/models/para/component/form.rb +36 -0
- data/app/models/para/component/resource.rb +9 -20
- data/app/models/para/component/settings.rb +1 -1
- data/app/models/para/library/file.rb +23 -0
- data/app/models/para/library.rb +5 -0
- data/app/views/para/admin/form_resources/show.html.haml +4 -0
- data/app/views/para/admin/imports/_completed.html.haml +16 -0
- data/app/views/para/admin/imports/_failed.html.haml +7 -0
- data/app/views/para/admin/imports/_progress.html.haml +5 -0
- data/app/views/para/admin/imports/new.html.haml +14 -0
- data/app/views/para/admin/imports/show.html.haml +10 -0
- data/app/views/para/admin/resources/_fields.html.haml +1 -4
- data/app/views/para/admin/resources/_imports_menu.html.haml +17 -20
- data/app/views/para/admin/resources/_tree.html.haml +1 -1
- data/app/views/para/admin/shared/_breadcrumbs.html.haml +1 -4
- data/app/views/para/admin/shared/_navigation.html.haml +2 -2
- data/app/views/para/form/_tabs.html.haml +1 -1
- data/config/locales/en.yml +10 -0
- data/config/locales/fr.yml +12 -2
- data/db/migrate/20160905134106_create_para_library_files.rb +9 -0
- data/lib/generators/para/importer/templates/base_importer.rb +8 -1
- data/lib/generators/para/install/install_generator.rb +1 -2
- data/lib/generators/para/install/templates/components.rb +9 -5
- data/lib/generators/para/tree_item/tree_item_generator.rb +17 -0
- data/lib/para/attribute_field/base.rb +12 -4
- data/lib/para/attribute_field/enum.rb +7 -3
- data/lib/para/component/importable.rb +4 -4
- data/lib/para/component.rb +1 -1
- data/lib/para/components_cleaner.rb +66 -0
- data/lib/para/components_configuration.rb +3 -1
- data/lib/para/engine.rb +36 -3
- data/lib/para/ext/active_job_status.rb +13 -0
- data/lib/para/ext/paperclip.rb +10 -0
- data/lib/para/ext/simple_form_extension.rb +6 -0
- data/lib/para/ext.rb +1 -0
- data/lib/para/form_builder/nested_form.rb +5 -2
- data/lib/para/importer/base.rb +84 -7
- data/lib/para/inputs/nested_many_input.rb +1 -1
- data/lib/para/logging/active_job_log_subscriber.rb +48 -0
- data/lib/para/logging.rb +8 -0
- data/lib/para/markup/resources_table.rb +2 -4
- data/lib/para/model_field_parsers/enums.rb +19 -0
- data/lib/para/model_field_parsers/relations.rb +1 -1
- data/lib/para/model_field_parsers/store.rb +1 -1
- data/lib/para/model_field_parsers.rb +1 -0
- data/lib/para/plugins/routes.rb +2 -4
- data/lib/para/postgres_extensions_checker.rb +30 -0
- data/lib/para/routes.rb +5 -4
- data/lib/para/routing/component_controller_constraint.rb +36 -0
- data/lib/para/routing.rb +7 -0
- data/lib/para/sti/root_model.rb +8 -2
- data/lib/para/version.rb +1 -1
- data/lib/para.rb +10 -0
- data/lib/rails/routing_mapper.rb +59 -27
- data/lib/tasks/para_tasks.rake +21 -11
- metadata +73 -15
- data/app/models/para/component/singleton_resource.rb +0 -35
- data/app/views/para/admin/singleton_resources/show.html.haml +0 -4
@@ -6,16 +6,20 @@ module Para
|
|
6
6
|
def value_for(instance)
|
7
7
|
if (raw_value = instance.send(name)) &&
|
8
8
|
path = enum_path_for(instance, raw_value)
|
9
|
-
translation = ::I18n.t("activerecord.#{ path }", default:
|
9
|
+
translation = ::I18n.t("activerecord.#{ path }", default: '')
|
10
10
|
|
11
|
-
translation || raw_value
|
11
|
+
translation.presence || raw_value
|
12
12
|
end
|
13
13
|
end
|
14
14
|
|
15
|
+
def field_type
|
16
|
+
:selectize
|
17
|
+
end
|
18
|
+
|
15
19
|
private
|
16
20
|
|
17
21
|
def enum_path_for(instance, key)
|
18
|
-
['enums', instance.
|
22
|
+
['enums', instance.model_name.i18n_key, name, key].join('.')
|
19
23
|
end
|
20
24
|
end
|
21
25
|
end
|
@@ -8,14 +8,14 @@ module Para
|
|
8
8
|
end
|
9
9
|
|
10
10
|
def importable?
|
11
|
-
@importable ||=
|
11
|
+
@importable ||= importers.length > 0
|
12
12
|
end
|
13
13
|
|
14
14
|
# TODO : Move :configuration column store to JSON instead of HStore
|
15
15
|
# which handles more data types and will help us avoid eval here
|
16
|
-
def
|
17
|
-
@
|
18
|
-
eval(importers)
|
16
|
+
def importers
|
17
|
+
@importers ||= if (importers = configuration['importers'].presence)
|
18
|
+
eval(importers).map(&:constantize)
|
19
19
|
else
|
20
20
|
[]
|
21
21
|
end
|
data/lib/para/component.rb
CHANGED
@@ -0,0 +1,66 @@
|
|
1
|
+
module Para
|
2
|
+
class ComponentsCleaner
|
3
|
+
# Hide class instanciation
|
4
|
+
def self.run; new.run; end
|
5
|
+
|
6
|
+
def run
|
7
|
+
components.each do |component|
|
8
|
+
unless component == Para.components.component_for(component.identifier)
|
9
|
+
component.destroy
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
Para::ComponentSection.find_each do |section|
|
14
|
+
unless Para.components.section_for(section.identifier)
|
15
|
+
section.destroy
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
private
|
21
|
+
|
22
|
+
def components
|
23
|
+
Para::Component::Base.all.to_a
|
24
|
+
rescue ActiveRecord::SubclassNotFound => e
|
25
|
+
# When a subclass is not found, define it and try loading all components.
|
26
|
+
#
|
27
|
+
# Since we're probably about to destroy this class, this sould not
|
28
|
+
# produce errors for the end user
|
29
|
+
#
|
30
|
+
if (match = e.message.match(/the subclass: '([\w:]+)'/))
|
31
|
+
define_temporary_component_subclass(match[1])
|
32
|
+
return components
|
33
|
+
end
|
34
|
+
|
35
|
+
raise e
|
36
|
+
end
|
37
|
+
|
38
|
+
def define_temporary_component_subclass(subclass_name)
|
39
|
+
subclass_path = subclass_name.split('::')
|
40
|
+
|
41
|
+
subclass_path.each_with_index.each_with_object([]) do |(const_name, index), path|
|
42
|
+
parent_name = path.join('::').presence
|
43
|
+
|
44
|
+
begin
|
45
|
+
[parent_name, const_name].compact.join('::').constantize
|
46
|
+
rescue NameError
|
47
|
+
# Last iterated constnat is the actual component subclass, others must
|
48
|
+
# be modules namespacing the component class
|
49
|
+
object = if index == (subclass_path.length - 1)
|
50
|
+
Class.new(Para::Component::Base)
|
51
|
+
else
|
52
|
+
Module.new
|
53
|
+
end
|
54
|
+
|
55
|
+
parent = parent_name ? parent_name.constantize : Object
|
56
|
+
# Define module or class in parent namespace
|
57
|
+
parent.const_set(const_name, object)
|
58
|
+
end
|
59
|
+
|
60
|
+
# Add const name to the path to allow namespaced constants to be
|
61
|
+
# defined in next loop iteration
|
62
|
+
path << const_name
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
@@ -86,6 +86,8 @@ module Para
|
|
86
86
|
end
|
87
87
|
|
88
88
|
tables_exist
|
89
|
+
rescue ActiveRecord::NoDatabaseError
|
90
|
+
false # Do not load components when the database is not installed
|
89
91
|
end
|
90
92
|
|
91
93
|
# Eager loads every file ending with _component.rb that's included in a
|
@@ -151,7 +153,7 @@ module Para
|
|
151
153
|
|
152
154
|
def refresh(attributes = {})
|
153
155
|
self.model = type.where(identifier: identifier).first_or_initialize
|
154
|
-
model.
|
156
|
+
model.update_with(attributes.merge(options_with_defaults))
|
155
157
|
model.save!
|
156
158
|
end
|
157
159
|
|
data/lib/para/engine.rb
CHANGED
@@ -29,7 +29,7 @@ module Para
|
|
29
29
|
end
|
30
30
|
|
31
31
|
initializer 'Extend paperclip attachment definition' do
|
32
|
-
|
32
|
+
next unless Kernel.const_defined?('Paperclip')
|
33
33
|
|
34
34
|
ActiveSupport.on_load(:active_record) do
|
35
35
|
::Paperclip::HasAttachedFile.send(
|
@@ -39,7 +39,7 @@ module Para
|
|
39
39
|
end
|
40
40
|
|
41
41
|
initializer 'Extend cancan ControllerResource class' do
|
42
|
-
|
42
|
+
next unless Kernel.const_defined?('CanCan')
|
43
43
|
|
44
44
|
ActiveSupport.on_load(:active_record) do
|
45
45
|
::CanCan::ControllerResource.send(
|
@@ -56,6 +56,14 @@ module Para
|
|
56
56
|
end
|
57
57
|
end
|
58
58
|
|
59
|
+
initializer 'Extend active job status\' status class' do
|
60
|
+
ActiveSupport.on_load(:active_job) do
|
61
|
+
::ActiveJob::Status::Status.send(
|
62
|
+
:include, Para::Ext::ActiveJob::StatusMixin
|
63
|
+
)
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
59
67
|
initializer 'Build components tree' do |app|
|
60
68
|
components_config_path = Rails.root.join('config', 'components.rb')
|
61
69
|
|
@@ -65,7 +73,32 @@ module Para
|
|
65
73
|
end
|
66
74
|
|
67
75
|
initializer 'Load page sections' do |app|
|
68
|
-
|
76
|
+
app.config.to_prepare do
|
77
|
+
Para::Page::Section.eager_load!
|
78
|
+
end
|
79
|
+
end
|
80
|
+
|
81
|
+
initializer 'Check for extensions installation' do
|
82
|
+
Para::PostgresExtensionsChecker.check_all
|
83
|
+
end
|
84
|
+
|
85
|
+
initializer 'Configure ActiveJob' do
|
86
|
+
if ActiveSupport::Cache::NullStore === ActiveJob::Status.store
|
87
|
+
ActiveJob::Status.store = :memory_store
|
88
|
+
end
|
89
|
+
|
90
|
+
Para::Logging::ActiveJobLogSubscriber.attach_to :active_job
|
91
|
+
end
|
92
|
+
|
93
|
+
# Allow generating resources in the gem without having all the unnecessary
|
94
|
+
# files generated
|
95
|
+
#
|
96
|
+
config.generators do |generators|
|
97
|
+
generators.skip_routes true if generators.respond_to?(:skip_routes)
|
98
|
+
generators.helper false
|
99
|
+
generators.stylesheets false
|
100
|
+
generators.javascripts false
|
101
|
+
generators.test_framework false
|
69
102
|
end
|
70
103
|
end
|
71
104
|
end
|
data/lib/para/ext/paperclip.rb
CHANGED
data/lib/para/ext.rb
CHANGED
@@ -56,7 +56,7 @@ module Para
|
|
56
56
|
return false unless nested?
|
57
57
|
|
58
58
|
reflection = parent_object.class.reflect_on_association(nested_attribute_name)
|
59
|
-
reflection && (reflection.options[:inverse_of] == field_name)
|
59
|
+
reflection && (reflection.options[:inverse_of].to_s == field_name.to_s)
|
60
60
|
end
|
61
61
|
|
62
62
|
def nested?
|
@@ -64,7 +64,10 @@ module Para
|
|
64
64
|
end
|
65
65
|
|
66
66
|
def nested_attribute_name
|
67
|
-
options[:nested_attribute_name]
|
67
|
+
options[:nested_attribute_name] ||=
|
68
|
+
if (match = object_name.match(/\[(\w+)_attributes\]/))
|
69
|
+
match[1]
|
70
|
+
end
|
68
71
|
end
|
69
72
|
|
70
73
|
def parent_object
|
data/lib/para/importer/base.rb
CHANGED
@@ -1,23 +1,100 @@
|
|
1
1
|
module Para
|
2
2
|
module Importer
|
3
|
-
class Base
|
4
|
-
|
3
|
+
class Base < ActiveJob::Base
|
4
|
+
include ActiveJob::Status
|
5
|
+
# Used to store import errors on the object
|
6
|
+
include ActiveModel::Validations
|
7
|
+
# Used to translate importer name with rails default `activemodel` i18n keys
|
8
|
+
extend ActiveModel::Naming
|
5
9
|
|
6
|
-
|
7
|
-
|
8
|
-
|
10
|
+
rescue_from Exception, with: :rescue_exception
|
11
|
+
|
12
|
+
class_attribute :allows_import_errors
|
13
|
+
|
14
|
+
attr_reader :file, :sheet
|
15
|
+
|
16
|
+
def perform(file, options = {})
|
17
|
+
@file = file
|
18
|
+
@sheet = Roo::Spreadsheet.open(file.attachment_path, options)
|
19
|
+
progress.total = sheet.last_row - 1
|
9
20
|
|
10
|
-
def run
|
11
21
|
ActiveRecord::Base.transaction do
|
12
22
|
(2..(sheet.last_row)).each do |index|
|
13
|
-
|
23
|
+
begin
|
24
|
+
progress.increment
|
25
|
+
import_from_row(sheet.row(index))
|
26
|
+
rescue ActiveRecord::RecordInvalid => error
|
27
|
+
if allows_import_errors?
|
28
|
+
add_errors_from(index, error.record)
|
29
|
+
else
|
30
|
+
raise
|
31
|
+
end
|
32
|
+
end
|
14
33
|
end
|
15
34
|
end
|
35
|
+
|
36
|
+
status.update(errors: errors.full_messages)
|
16
37
|
end
|
17
38
|
|
39
|
+
private
|
40
|
+
|
18
41
|
def import_from_row(row)
|
19
42
|
raise '#import_from_row(row) must be defined'
|
20
43
|
end
|
44
|
+
|
45
|
+
def add_errors_from(index, record)
|
46
|
+
# The file's row number starts at 1 and headers are striped, so we
|
47
|
+
# add 2 to the index to obtain the row number
|
48
|
+
row_name = I18n.t('para.import.row_error_prefix', number: index)
|
49
|
+
|
50
|
+
record.errors.messages.each do |attribute, messages|
|
51
|
+
messages.each do |message|
|
52
|
+
full_message = record.errors.full_message(attribute, message)
|
53
|
+
|
54
|
+
if (value = record.send(attribute)).presence
|
55
|
+
full_message << ' (<b>' << value << '</b>)'
|
56
|
+
end
|
57
|
+
|
58
|
+
errors.add(row_name, full_message)
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
def allows_import_errors?
|
64
|
+
!!self.class.allows_import_errors
|
65
|
+
end
|
66
|
+
|
67
|
+
def self.allow_import_errors!
|
68
|
+
self.allows_import_errors = true
|
69
|
+
end
|
70
|
+
|
71
|
+
def headers
|
72
|
+
@headers ||= sheet.row(1)
|
73
|
+
end
|
74
|
+
|
75
|
+
def rescue_exception(exception)
|
76
|
+
status.update(status: :failed)
|
77
|
+
|
78
|
+
tag_logger(self.class.name, self.job_id) do
|
79
|
+
ActiveSupport::Notifications.instrument "failed.active_job",
|
80
|
+
adapter: self.class.queue_adapter, job: self, exception: exception
|
81
|
+
end
|
82
|
+
|
83
|
+
if defined?(ExceptionNotifier)
|
84
|
+
ExceptionNotifier.notify_exception(
|
85
|
+
exception, data: {
|
86
|
+
importer: self.class.name,
|
87
|
+
payload: {
|
88
|
+
file_type: file.class,
|
89
|
+
file_id: file.id,
|
90
|
+
file_name: file.attachment_file_name
|
91
|
+
}
|
92
|
+
}
|
93
|
+
)
|
94
|
+
end
|
95
|
+
|
96
|
+
raise exception
|
97
|
+
end
|
21
98
|
end
|
22
99
|
end
|
23
100
|
end
|
@@ -11,7 +11,7 @@ module Para
|
|
11
11
|
# Load existing resources
|
12
12
|
resources = object.send(attribute_name)
|
13
13
|
# Order them if the list should be orderable
|
14
|
-
resources = resources.
|
14
|
+
resources = resources.sort_by(&:position) if orderable
|
15
15
|
|
16
16
|
locals = options.fetch(:locals, {})
|
17
17
|
|
@@ -0,0 +1,48 @@
|
|
1
|
+
module Para
|
2
|
+
module Logging
|
3
|
+
class ActiveJobLogSubscriber < ActiveSupport::LogSubscriber
|
4
|
+
def failed(event)
|
5
|
+
fatal do
|
6
|
+
job = event.payload[:job]
|
7
|
+
buffer = []
|
8
|
+
buffer << "#{ job.class.name } (Job ID: #{ job.job_id }) failed" + args_info(job)
|
9
|
+
buffer << ''
|
10
|
+
buffer << [event.payload[:exception].class, event.payload[:exception].message].join(' - ')
|
11
|
+
buffer << ''
|
12
|
+
buffer << '-------------------'
|
13
|
+
buffer << ''
|
14
|
+
buffer += event.payload[:exception].backtrace
|
15
|
+
buffer << ''
|
16
|
+
buffer.compact.join("\n")
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
private
|
21
|
+
|
22
|
+
def args_info(job)
|
23
|
+
if job.arguments.any?
|
24
|
+
' with arguments: ' +
|
25
|
+
job.arguments.map { |arg| format(arg).inspect }.join(', ')
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
def format(arg)
|
30
|
+
case arg
|
31
|
+
when Hash
|
32
|
+
arg.transform_values { |value| format(value) }
|
33
|
+
when Array
|
34
|
+
arg.map { |value| format(value) }
|
35
|
+
when GlobalID::Identification
|
36
|
+
arg.to_global_id rescue arg
|
37
|
+
else
|
38
|
+
arg
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
def logger
|
43
|
+
ActiveJob::Base.logger
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
data/lib/para/logging.rb
ADDED
@@ -79,8 +79,6 @@ module Para
|
|
79
79
|
field_name = nil
|
80
80
|
end
|
81
81
|
|
82
|
-
sort = options.delete(:sort) || field_name
|
83
|
-
|
84
82
|
label = if Symbol === field_name
|
85
83
|
model.human_attribute_name(field_name)
|
86
84
|
elsif block
|
@@ -90,7 +88,7 @@ module Para
|
|
90
88
|
end
|
91
89
|
|
92
90
|
content_tag(:th, options) do
|
93
|
-
if sort
|
91
|
+
if (sort = options.delete(:sort))
|
94
92
|
view.sort_link(search, *sort, label, hide_indicator: true)
|
95
93
|
elsif searchable?(field_name)
|
96
94
|
view.sort_link(search, field_name, label, hide_indicator: true)
|
@@ -155,7 +153,7 @@ module Para
|
|
155
153
|
}
|
156
154
|
|
157
155
|
view.link_to(path, options) do
|
158
|
-
content_tag(:i, '', class: 'fa fa-
|
156
|
+
content_tag(:i, '', class: 'fa fa-copy')
|
159
157
|
end
|
160
158
|
end
|
161
159
|
|
@@ -0,0 +1,19 @@
|
|
1
|
+
module Para
|
2
|
+
module ModelFieldParsers
|
3
|
+
class Enums < Para::ModelFieldParsers::Base
|
4
|
+
register :enums, self
|
5
|
+
|
6
|
+
def parse!
|
7
|
+
model.defined_enums.each do |key, _|
|
8
|
+
fields_hash[key] = AttributeField::EnumField.new(
|
9
|
+
model, name: key, type: 'enum'
|
10
|
+
)
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
def applicable?
|
15
|
+
model.respond_to?(:defined_enums) && !model.defined_enums.empty?
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
@@ -38,7 +38,7 @@ module Para
|
|
38
38
|
fields_hash[name] = AttributeField::HasManyField.new(
|
39
39
|
model, name: name, type: 'has_many', field_type: 'selectize'
|
40
40
|
)
|
41
|
-
|
41
|
+
elsif !reflection.options[:through]
|
42
42
|
fields_hash[name] = AttributeField::BelongsToField.new(
|
43
43
|
model, name: name, type: 'belongs_to', field_type: 'selectize'
|
44
44
|
)
|
data/lib/para/plugins/routes.rb
CHANGED
@@ -13,10 +13,8 @@ module Para
|
|
13
13
|
router = self.router
|
14
14
|
|
15
15
|
router.instance_eval do
|
16
|
-
|
17
|
-
|
18
|
-
router.instance_eval(&block)
|
19
|
-
end
|
16
|
+
scope module: [:para, identifier].join('/').to_sym do
|
17
|
+
router.instance_eval(&block)
|
20
18
|
end
|
21
19
|
end
|
22
20
|
end
|
@@ -0,0 +1,30 @@
|
|
1
|
+
module Para
|
2
|
+
class PostgresExtensionsChecker
|
3
|
+
class << self
|
4
|
+
def check_all
|
5
|
+
%w(hstore unaccent).each do |extname|
|
6
|
+
unless extension_exists?(extname)
|
7
|
+
# Could not use Rails.logger here, using puts as a temporary
|
8
|
+
# solution.
|
9
|
+
puts "[Warning] PostgreSQL \"#{ extname }\" extension is not " +
|
10
|
+
"installed in your database. This means that you " +
|
11
|
+
"missing some migrations that you can install " +
|
12
|
+
"with the following command : " +
|
13
|
+
"`rake para_engine:install:migrations` and then migrate."
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
private
|
19
|
+
|
20
|
+
def extension_exists?(extname)
|
21
|
+
ActiveRecord::Base.connection.execute(
|
22
|
+
"SELECT COUNT(*) FROM pg_catalog.pg_extension " +
|
23
|
+
"WHERE extname = '#{ extname }'"
|
24
|
+
).first['count'].to_i > 0
|
25
|
+
rescue ActiveRecord::NoDatabaseError
|
26
|
+
true # Do not issue warning when no database is installed
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
data/lib/para/routes.rb
CHANGED
@@ -14,11 +14,12 @@ module Para
|
|
14
14
|
scope module: :para do
|
15
15
|
namespace :admin do
|
16
16
|
get '/' => 'main#index'
|
17
|
-
|
18
|
-
crud_component :crud, scope: ':model'
|
19
|
-
singleton_resource_component :singleton, scope: ':model'
|
20
|
-
component :settings
|
21
17
|
end
|
18
|
+
|
19
|
+
# Components are namespaced into :admin in their respective methods
|
20
|
+
crud_component
|
21
|
+
form_component
|
22
|
+
component :settings
|
22
23
|
end
|
23
24
|
|
24
25
|
block.call if block
|
@@ -0,0 +1,36 @@
|
|
1
|
+
# Allows constraining routing to components that explicitly declares to use a
|
2
|
+
# given controller to manage their resources.
|
3
|
+
#
|
4
|
+
# It's mainly used to allow users to override the default controller for the
|
5
|
+
# resources of a given Crud or Form components without having to
|
6
|
+
# subclass the component and declare all the routes again
|
7
|
+
#
|
8
|
+
module Para
|
9
|
+
module Routing
|
10
|
+
class ComponentControllerConstraint
|
11
|
+
attr_reader :controller
|
12
|
+
|
13
|
+
def initialize(controller)
|
14
|
+
@controller = controller.to_sym
|
15
|
+
end
|
16
|
+
|
17
|
+
def matches?(request)
|
18
|
+
component = component_for(request.params[:component_id])
|
19
|
+
return false unless component
|
20
|
+
component.controller.to_sym == controller
|
21
|
+
end
|
22
|
+
|
23
|
+
private
|
24
|
+
|
25
|
+
def component_for(component_slug)
|
26
|
+
self.class.components[component_slug] ||= Para::Component::Base.find_by_slug(component_slug)
|
27
|
+
end
|
28
|
+
|
29
|
+
# Request based components cache
|
30
|
+
#
|
31
|
+
def self.components
|
32
|
+
RequestStore.store['para.components_by_id'] ||= {}
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
data/lib/para/routing.rb
ADDED
data/lib/para/sti/root_model.rb
CHANGED
@@ -16,8 +16,8 @@ module Para
|
|
16
16
|
|
17
17
|
module ClassMethods
|
18
18
|
def eager_load!
|
19
|
-
return if
|
20
|
-
|
19
|
+
return if RequestStore.store[descendants_eager_load_key]
|
20
|
+
RequestStore.store[descendants_eager_load_key] = true
|
21
21
|
|
22
22
|
models_dir = Rails.root.join('app', 'models')
|
23
23
|
|
@@ -38,6 +38,12 @@ module Para
|
|
38
38
|
|
39
39
|
private
|
40
40
|
|
41
|
+
def descendants_eager_load_key
|
42
|
+
@descendants_eager_load_key ||= [
|
43
|
+
'para', 'root_model', 'descendants_eager_loaded', name
|
44
|
+
].join(':')
|
45
|
+
end
|
46
|
+
|
41
47
|
# Allows the including class to define `.subclasses_namespace` class
|
42
48
|
# method to override the namespace and directory used to eager load the
|
43
49
|
# subclasses.
|
data/lib/para/version.rb
CHANGED