wallaby 4.1.6
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/MIT-LICENSE +20 -0
- data/Rakefile +29 -0
- data/app/assets/javascripts/wallaby/application.js +15 -0
- data/app/assets/javascripts/wallaby/form.js +8 -0
- data/app/assets/stylesheets/wallaby/application.scss +51 -0
- data/app/assets/stylesheets/wallaby/base/_functions.scss +0 -0
- data/app/assets/stylesheets/wallaby/base/_layout.scss +14 -0
- data/app/assets/stylesheets/wallaby/base/_mixins.scss +0 -0
- data/app/assets/stylesheets/wallaby/base/_normalize.scss +0 -0
- data/app/assets/stylesheets/wallaby/base/_reset.scss +0 -0
- data/app/assets/stylesheets/wallaby/base/_vars.scss +5 -0
- data/app/assets/stylesheets/wallaby/components/_forms.scss +53 -0
- data/app/assets/stylesheets/wallaby/components/_nav.scss +19 -0
- data/app/assets/stylesheets/wallaby/components/_pagination.scss +105 -0
- data/app/assets/stylesheets/wallaby/components/_tables.scss +78 -0
- data/app/assets/stylesheets/wallaby/components/_text.scss +11 -0
- data/app/assets/stylesheets/wallaby/form.scss +11 -0
- data/app/assets/stylesheets/wallaby/summernote.scss.erb +7 -0
- data/app/controllers/wallaby/application_controller.rb +21 -0
- data/app/controllers/wallaby/core_controller.rb +28 -0
- data/app/controllers/wallaby/resources_controller.rb +134 -0
- data/app/controllers/wallaby/secure_controller.rb +42 -0
- data/app/routes/wallaby/resources_router.rb +52 -0
- data/app/security/ability.rb +33 -0
- data/app/views/layouts/wallaby/_footer.html.erb +2 -0
- data/app/views/layouts/wallaby/_header.html.erb +57 -0
- data/app/views/layouts/wallaby/_navs.html.erb +1 -0
- data/app/views/layouts/wallaby/application.html.erb +22 -0
- data/app/views/layouts/wallaby/error.html.erb +20 -0
- data/app/views/wallaby/core/home.html.erb +5 -0
- data/app/views/wallaby/errors/access_denied.html.erb +1 -0
- data/app/views/wallaby/errors/not_authenticated.html.erb +1 -0
- data/app/views/wallaby/errors/not_found.html.erb +6 -0
- data/app/views/wallaby/errors/unprocessable_entity.erb +1 -0
- data/app/views/wallaby/resources/_form.html.erb +12 -0
- data/app/views/wallaby/resources/_index_actions.html.erb +1 -0
- data/app/views/wallaby/resources/_resource_actions.html.erb +3 -0
- data/app/views/wallaby/resources/edit.html.erb +14 -0
- data/app/views/wallaby/resources/form/_belongs_to.html.erb +21 -0
- data/app/views/wallaby/resources/form/_bigint.html.erb +9 -0
- data/app/views/wallaby/resources/form/_binary.html.erb +12 -0
- data/app/views/wallaby/resources/form/_bit.html.erb +9 -0
- data/app/views/wallaby/resources/form/_bit_varying.html.erb +9 -0
- data/app/views/wallaby/resources/form/_boolean.html.erb +14 -0
- data/app/views/wallaby/resources/form/_cidr.html.erb +9 -0
- data/app/views/wallaby/resources/form/_citext.html.erb +21 -0
- data/app/views/wallaby/resources/form/_color.html.erb +20 -0
- data/app/views/wallaby/resources/form/_date.html.erb +29 -0
- data/app/views/wallaby/resources/form/_daterange.html.erb +37 -0
- data/app/views/wallaby/resources/form/_datetime.html.erb +30 -0
- data/app/views/wallaby/resources/form/_decimal.html.erb +9 -0
- data/app/views/wallaby/resources/form/_email.html.erb +5 -0
- data/app/views/wallaby/resources/form/_float.html.erb +9 -0
- data/app/views/wallaby/resources/form/_has_and_belongs_to_many.html.erb +13 -0
- data/app/views/wallaby/resources/form/_has_many.html.erb +13 -0
- data/app/views/wallaby/resources/form/_has_one.html.erb +7 -0
- data/app/views/wallaby/resources/form/_hstore.html.erb +25 -0
- data/app/views/wallaby/resources/form/_inet.html.erb +9 -0
- data/app/views/wallaby/resources/form/_int4range.html.erb +18 -0
- data/app/views/wallaby/resources/form/_int8range.html.erb +18 -0
- data/app/views/wallaby/resources/form/_integer.html.erb +9 -0
- data/app/views/wallaby/resources/form/_json.html.erb +23 -0
- data/app/views/wallaby/resources/form/_jsonb.html.erb +23 -0
- data/app/views/wallaby/resources/form/_ltree.html.erb +5 -0
- data/app/views/wallaby/resources/form/_macaddr.html.erb +9 -0
- data/app/views/wallaby/resources/form/_money.html.erb +12 -0
- data/app/views/wallaby/resources/form/_numrange.html.erb +18 -0
- data/app/views/wallaby/resources/form/_password.html.erb +5 -0
- data/app/views/wallaby/resources/form/_point.html.erb +18 -0
- data/app/views/wallaby/resources/form/_string.html.erb +5 -0
- data/app/views/wallaby/resources/form/_text.html.erb +21 -0
- data/app/views/wallaby/resources/form/_time.html.erb +29 -0
- data/app/views/wallaby/resources/form/_tsrange.html.erb +38 -0
- data/app/views/wallaby/resources/form/_tstzrange.html.erb +38 -0
- data/app/views/wallaby/resources/form/_tsvector.html.erb +5 -0
- data/app/views/wallaby/resources/form/_uuid.html.erb +9 -0
- data/app/views/wallaby/resources/form/_xml.html.erb +23 -0
- data/app/views/wallaby/resources/index/_belongs_to.html.erb +1 -0
- data/app/views/wallaby/resources/index/_bigint.html.erb +1 -0
- data/app/views/wallaby/resources/index/_binary.html.erb +1 -0
- data/app/views/wallaby/resources/index/_bit.html.erb +5 -0
- data/app/views/wallaby/resources/index/_bit_varying.html.erb +5 -0
- data/app/views/wallaby/resources/index/_boolean.html.erb +5 -0
- data/app/views/wallaby/resources/index/_cidr.html.erb +6 -0
- data/app/views/wallaby/resources/index/_citext.html.erb +12 -0
- data/app/views/wallaby/resources/index/_color.html.erb +5 -0
- data/app/views/wallaby/resources/index/_date.html.erb +7 -0
- data/app/views/wallaby/resources/index/_daterange.html.erb +8 -0
- data/app/views/wallaby/resources/index/_datetime.html.erb +7 -0
- data/app/views/wallaby/resources/index/_decimal.html.erb +1 -0
- data/app/views/wallaby/resources/index/_email.html.erb +1 -0
- data/app/views/wallaby/resources/index/_float.html.erb +1 -0
- data/app/views/wallaby/resources/index/_has_and_belongs_to_many.html.erb +11 -0
- data/app/views/wallaby/resources/index/_has_many.html.erb +11 -0
- data/app/views/wallaby/resources/index/_has_one.html.erb +1 -0
- data/app/views/wallaby/resources/index/_hstore.html.erb +12 -0
- data/app/views/wallaby/resources/index/_inet.html.erb +6 -0
- data/app/views/wallaby/resources/index/_int4range.html.erb +7 -0
- data/app/views/wallaby/resources/index/_int8range.html.erb +7 -0
- data/app/views/wallaby/resources/index/_integer.html.erb +1 -0
- data/app/views/wallaby/resources/index/_json.html.erb +12 -0
- data/app/views/wallaby/resources/index/_jsonb.html.erb +12 -0
- data/app/views/wallaby/resources/index/_ltree.html.erb +12 -0
- data/app/views/wallaby/resources/index/_macaddr.html.erb +5 -0
- data/app/views/wallaby/resources/index/_money.html.erb +1 -0
- data/app/views/wallaby/resources/index/_numrange.html.erb +7 -0
- data/app/views/wallaby/resources/index/_point.html.erb +6 -0
- data/app/views/wallaby/resources/index/_string.html.erb +12 -0
- data/app/views/wallaby/resources/index/_text.html.erb +12 -0
- data/app/views/wallaby/resources/index/_time.html.erb +6 -0
- data/app/views/wallaby/resources/index/_tsrange.html.erb +8 -0
- data/app/views/wallaby/resources/index/_tstzrange.html.erb +8 -0
- data/app/views/wallaby/resources/index/_tsvector.html.erb +12 -0
- data/app/views/wallaby/resources/index/_uuid.html.erb +12 -0
- data/app/views/wallaby/resources/index/_xml.html.erb +12 -0
- data/app/views/wallaby/resources/index.html.erb +66 -0
- data/app/views/wallaby/resources/new.html.erb +14 -0
- data/app/views/wallaby/resources/shared/_resource_nav.html.erb +29 -0
- data/app/views/wallaby/resources/show/_belongs_to.html.erb +7 -0
- data/app/views/wallaby/resources/show/_bigint.html.erb +1 -0
- data/app/views/wallaby/resources/show/_binary.html.erb +1 -0
- data/app/views/wallaby/resources/show/_bit.html.erb +5 -0
- data/app/views/wallaby/resources/show/_bit_varying.html.erb +5 -0
- data/app/views/wallaby/resources/show/_boolean.html.erb +5 -0
- data/app/views/wallaby/resources/show/_cidr.html.erb +6 -0
- data/app/views/wallaby/resources/show/_citext.html.erb +1 -0
- data/app/views/wallaby/resources/show/_color.html.erb +5 -0
- data/app/views/wallaby/resources/show/_date.html.erb +7 -0
- data/app/views/wallaby/resources/show/_daterange.html.erb +7 -0
- data/app/views/wallaby/resources/show/_datetime.html.erb +6 -0
- data/app/views/wallaby/resources/show/_decimal.html.erb +1 -0
- data/app/views/wallaby/resources/show/_email.html.erb +1 -0
- data/app/views/wallaby/resources/show/_float.html.erb +1 -0
- data/app/views/wallaby/resources/show/_has_and_belongs_to_many.html.erb +5 -0
- data/app/views/wallaby/resources/show/_has_many.html.erb +5 -0
- data/app/views/wallaby/resources/show/_has_one.html.erb +1 -0
- data/app/views/wallaby/resources/show/_hstore.html.erb +5 -0
- data/app/views/wallaby/resources/show/_inet.html.erb +6 -0
- data/app/views/wallaby/resources/show/_int4range.html.erb +7 -0
- data/app/views/wallaby/resources/show/_int8range.html.erb +7 -0
- data/app/views/wallaby/resources/show/_integer.html.erb +1 -0
- data/app/views/wallaby/resources/show/_json.html.erb +5 -0
- data/app/views/wallaby/resources/show/_jsonb.html.erb +5 -0
- data/app/views/wallaby/resources/show/_ltree.html.erb +1 -0
- data/app/views/wallaby/resources/show/_macaddr.html.erb +5 -0
- data/app/views/wallaby/resources/show/_money.html.erb +1 -0
- data/app/views/wallaby/resources/show/_numrange.html.erb +7 -0
- data/app/views/wallaby/resources/show/_point.html.erb +6 -0
- data/app/views/wallaby/resources/show/_string.html.erb +1 -0
- data/app/views/wallaby/resources/show/_text.html.erb +1 -0
- data/app/views/wallaby/resources/show/_time.html.erb +6 -0
- data/app/views/wallaby/resources/show/_tsrange.html.erb +7 -0
- data/app/views/wallaby/resources/show/_tstzrange.html.erb +7 -0
- data/app/views/wallaby/resources/show/_tsvector.html.erb +1 -0
- data/app/views/wallaby/resources/show/_uuid.html.erb +5 -0
- data/app/views/wallaby/resources/show/_xml.html.erb +5 -0
- data/app/views/wallaby/resources/show.html.erb +31 -0
- data/app/views/wallaby/shared/_flash_messages.html.erb +13 -0
- data/config/locales/en.yml +29 -0
- data/config/routes.rb +34 -0
- data/lib/adaptors/wallaby/active_record/model_decorator/fields_builder.rb +105 -0
- data/lib/adaptors/wallaby/active_record/model_decorator/title_field_finder.rb +18 -0
- data/lib/adaptors/wallaby/active_record/model_decorator.rb +81 -0
- data/lib/adaptors/wallaby/active_record/model_finder.rb +12 -0
- data/lib/adaptors/wallaby/active_record/model_operator/normalizer.rb +44 -0
- data/lib/adaptors/wallaby/active_record/model_operator/permitter.rb +50 -0
- data/lib/adaptors/wallaby/active_record/model_operator/querier.rb +47 -0
- data/lib/adaptors/wallaby/active_record/model_operator/validator.rb +16 -0
- data/lib/adaptors/wallaby/active_record/model_operator.rb +82 -0
- data/lib/adaptors/wallaby/active_record.rb +2 -0
- data/lib/decorators/wallaby/resource_decorator.rb +78 -0
- data/lib/errors/wallaby/deprecated.rb +4 -0
- data/lib/errors/wallaby/general_error.rb +4 -0
- data/lib/errors/wallaby/invalid_error.rb +4 -0
- data/lib/errors/wallaby/model_not_found.rb +4 -0
- data/lib/errors/wallaby/not_authenticated.rb +4 -0
- data/lib/errors/wallaby/not_implemented.rb +4 -0
- data/lib/errors/wallaby/operation_not_found.rb +4 -0
- data/lib/errors/wallaby/resource_not_found.rb +4 -0
- data/lib/forms/wallaby/form_builder.rb +30 -0
- data/lib/handlers/wallaby/cached_compiled_erb.rb +14 -0
- data/lib/helpers/wallaby/application_helper.rb +30 -0
- data/lib/helpers/wallaby/core_helper.rb +50 -0
- data/lib/helpers/wallaby/form_helper.rb +21 -0
- data/lib/helpers/wallaby/links_helper.rb +83 -0
- data/lib/helpers/wallaby/paginatable_helper.rb +9 -0
- data/lib/helpers/wallaby/resources_helper.rb +55 -0
- data/lib/helpers/wallaby/secure_helper.rb +25 -0
- data/lib/helpers/wallaby/sorting_helper.rb +43 -0
- data/lib/helpers/wallaby/styling_helper.rb +57 -0
- data/lib/interfaces/wallaby/mode.rb +18 -0
- data/lib/interfaces/wallaby/model_decorator.rb +58 -0
- data/lib/interfaces/wallaby/model_finder.rb +5 -0
- data/lib/interfaces/wallaby/model_operator.rb +31 -0
- data/lib/services/wallaby/decorator_finder.rb +16 -0
- data/lib/services/wallaby/lookup_context_wrapper.rb +40 -0
- data/lib/services/wallaby/map.rb +53 -0
- data/lib/services/wallaby/model_servicer.rb +38 -0
- data/lib/services/wallaby/servicer_finder.rb +5 -0
- data/lib/tasks/wallaby_tasks.rake +4 -0
- data/lib/utils/wallaby/utils.rb +31 -0
- data/lib/wallaby/configuration/models.rb +17 -0
- data/lib/wallaby/configuration/security.rb +30 -0
- data/lib/wallaby/configuration.rb +49 -0
- data/lib/wallaby/engine.rb +89 -0
- data/lib/wallaby/version.rb +3 -0
- data/lib/wallaby.rb +5 -0
- metadata +459 -0
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
class Wallaby::ActiveRecord::ModelDecorator < Wallaby::ModelDecorator
|
|
2
|
+
def fields
|
|
3
|
+
@fields ||= {}.tap do |hash|
|
|
4
|
+
if model_class.table_exists?
|
|
5
|
+
hash.merge! general_fields
|
|
6
|
+
hash.merge! association_fields
|
|
7
|
+
hash.except! *foreign_keys_from_associations
|
|
8
|
+
end
|
|
9
|
+
end.with_indifferent_access
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
def index_fields
|
|
13
|
+
@index_fields ||= fields.deep_dup
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
def show_fields
|
|
17
|
+
@show_fields ||= fields.deep_dup
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
def form_fields
|
|
21
|
+
@form_fields ||= fields.deep_dup
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
def index_field_names
|
|
25
|
+
@index_field_names ||= index_fields.reject do |field_name, metadata|
|
|
26
|
+
metadata[:is_association] ||
|
|
27
|
+
%w( binary citext hstore json jsonb text tsvector xml ).include?(metadata[:type])
|
|
28
|
+
end.keys
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
def form_field_names
|
|
32
|
+
@form_field_names ||= form_fields.reject do |field_name, metadata|
|
|
33
|
+
%W( #{ primary_key } updated_at created_at ).include?(field_name) ||
|
|
34
|
+
metadata[:has_scope] ||
|
|
35
|
+
metadata[:is_through]
|
|
36
|
+
end.keys
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
def form_active_errors(resource)
|
|
40
|
+
resource.errors
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
def primary_key
|
|
44
|
+
@model_class.primary_key
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
def guess_title(resource)
|
|
48
|
+
resource.public_send title_field_finder.find
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
protected
|
|
52
|
+
def field_builder
|
|
53
|
+
@field_builder ||= Wallaby::ActiveRecord::ModelDecorator::FieldsBuilder.new @model_class
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
def title_field_finder
|
|
57
|
+
@title_field_finder ||= Wallaby::ActiveRecord::ModelDecorator::TitleFieldFinder.new @model_class, general_fields
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
delegate :general_fields, :association_fields, to: :field_builder
|
|
61
|
+
|
|
62
|
+
def foreign_keys_from_associations(associations = association_fields)
|
|
63
|
+
associations.inject([]) do |keys, (field_name, metadata)|
|
|
64
|
+
keys << metadata[:foreign_key] if metadata[:foreign_key]
|
|
65
|
+
keys << metadata[:polymorphic_type] if metadata[:polymorphic_type]
|
|
66
|
+
keys
|
|
67
|
+
end
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
def many_associations(associations = association_fields)
|
|
71
|
+
associations.select do |field_name, metadata|
|
|
72
|
+
/many/ =~ metadata[:type] && !metadata[:is_through]
|
|
73
|
+
end
|
|
74
|
+
end
|
|
75
|
+
|
|
76
|
+
def belongs_to_associations(associations = association_fields)
|
|
77
|
+
associations.select do |field_name, metadata|
|
|
78
|
+
'belongs_to' == metadata[:type]
|
|
79
|
+
end
|
|
80
|
+
end
|
|
81
|
+
end
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
class Wallaby::ActiveRecord::ModelFinder < Wallaby::ModelFinder
|
|
2
|
+
def all
|
|
3
|
+
Rails.cache.fetch 'wallaby/active_record/model_finder' do
|
|
4
|
+
ActiveRecord::Base.subclasses.reject do |model_class|
|
|
5
|
+
model_class.abstract_class? ||
|
|
6
|
+
model_class.to_s.start_with?('#<') ||
|
|
7
|
+
model_class.name == 'ActiveRecord::SchemaMigration' ||
|
|
8
|
+
model_class.name.index('HABTM')
|
|
9
|
+
end.sort_by &:to_s
|
|
10
|
+
end
|
|
11
|
+
end
|
|
12
|
+
end
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
class Wallaby::ActiveRecord::ModelOperator::Normalizer
|
|
2
|
+
def initialize(model_decorator)
|
|
3
|
+
@model_decorator = model_decorator
|
|
4
|
+
end
|
|
5
|
+
|
|
6
|
+
def normalize(params)
|
|
7
|
+
params.each do |field_name, values|
|
|
8
|
+
next unless metadata = @model_decorator.fields[field_name]
|
|
9
|
+
|
|
10
|
+
case metadata[:type]
|
|
11
|
+
when /range/
|
|
12
|
+
normalize_range_values params, field_name, values
|
|
13
|
+
when /point/
|
|
14
|
+
normalize_point_values params, field_name, values
|
|
15
|
+
when /binary/
|
|
16
|
+
normalize_binary_values params, field_name, values
|
|
17
|
+
end
|
|
18
|
+
end
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
def normalize_range_values(params, field_name, values)
|
|
22
|
+
normalized = Array(values).map(&:presence).compact
|
|
23
|
+
if normalized.length > 0 && values.length == 2
|
|
24
|
+
params[field_name] = values.first...values.last
|
|
25
|
+
else
|
|
26
|
+
params[field_name] = nil
|
|
27
|
+
end
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
def normalize_point_values(params, field_name, values)
|
|
31
|
+
normalized = Array(values).map(&:presence).compact
|
|
32
|
+
if normalized.length > 0
|
|
33
|
+
params[field_name] = values.map &:to_f
|
|
34
|
+
else
|
|
35
|
+
params[field_name] = nil
|
|
36
|
+
end
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
def normalize_binary_values(params, field_name, values)
|
|
40
|
+
if values.is_a?(ActionDispatch::Http::UploadedFile)
|
|
41
|
+
params[field_name] = values.read
|
|
42
|
+
end
|
|
43
|
+
end
|
|
44
|
+
end
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
class Wallaby::ActiveRecord::ModelOperator::Permitter
|
|
2
|
+
def initialize(model_decorator)
|
|
3
|
+
@model_decorator = model_decorator
|
|
4
|
+
end
|
|
5
|
+
|
|
6
|
+
def simple_field_names
|
|
7
|
+
field_names = non_range_fields.keys + belongs_to_fields.map do |_, metadata|
|
|
8
|
+
[ metadata[:foreign_key], metadata[:polymorphic_type] ]
|
|
9
|
+
end.flatten.compact
|
|
10
|
+
field_names.reject do |field_name|
|
|
11
|
+
[ @model_decorator.primary_key, 'created_at', 'updated_at' ].include? field_name
|
|
12
|
+
end
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
def compound_hashed_fields
|
|
16
|
+
field_names = range_fields.keys + many_association_fields.map{ |_, metadata| metadata[:foreign_key] }
|
|
17
|
+
Wallaby::Utils.to_hash(field_names.map{ |field_name| [ field_name, [] ] })
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
protected
|
|
21
|
+
def non_association_fields
|
|
22
|
+
@model_decorator.fields.select{ |_, metadata| !metadata[:is_association] }
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
def non_range_fields
|
|
26
|
+
non_association_fields.select{ |_, metadata| !(/range|point/ =~ metadata[:type]) }
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
def range_fields
|
|
30
|
+
non_association_fields.select do |_, metadata|
|
|
31
|
+
/range|point/ =~ metadata[:type]
|
|
32
|
+
end
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
def association_fields
|
|
36
|
+
@model_decorator.fields.select do |_, metadata|
|
|
37
|
+
metadata[:is_association] && !metadata[:has_scope] && !metadata[:is_through]
|
|
38
|
+
end
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
def many_association_fields
|
|
42
|
+
association_fields.select{ |_, metadata| /many/ =~ metadata[:type] }
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
def belongs_to_fields
|
|
46
|
+
association_fields.select do |field_name, metadata|
|
|
47
|
+
'belongs_to' == metadata[:type]
|
|
48
|
+
end
|
|
49
|
+
end
|
|
50
|
+
end
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
class Wallaby::ActiveRecord::ModelOperator::Querier
|
|
2
|
+
def initialize(model_decorator)
|
|
3
|
+
@model_decorator = model_decorator
|
|
4
|
+
@model_class = @model_decorator.model_class
|
|
5
|
+
end
|
|
6
|
+
|
|
7
|
+
def search(params)
|
|
8
|
+
text_keywords, field_keywords = extract params
|
|
9
|
+
query = @model_class.where nil
|
|
10
|
+
query = text_search text_keywords, query
|
|
11
|
+
query = field_search field_keywords, query
|
|
12
|
+
query
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
protected
|
|
16
|
+
def extract(params)
|
|
17
|
+
all_keywords = (params[:q] || '').split(' ').compact
|
|
18
|
+
field_keywords = all_keywords.select{ |v| v.split(':').length == 2 }
|
|
19
|
+
[ all_keywords - field_keywords, field_keywords ]
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
def text_search(keywords, query)
|
|
23
|
+
return query if keywords.blank?
|
|
24
|
+
|
|
25
|
+
queries = text_fields.inject([]) do |queries, field_name|
|
|
26
|
+
likes = keywords.map do |keyword|
|
|
27
|
+
[ "UPPER(#{ field_name }) LIKE ?", "%#{ keyword.upcase }%" ]
|
|
28
|
+
end
|
|
29
|
+
queries << [ "(#{ likes.map(&:first).join ' AND ' })", likes.map(&:last) ]
|
|
30
|
+
end
|
|
31
|
+
query.where queries.map(&:first).join(' OR '), *queries.map(&:last).flatten
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
def field_search(keywords, query)
|
|
35
|
+
return query if keywords.blank?
|
|
36
|
+
|
|
37
|
+
hashed_queries = Wallaby::Utils.to_hash(keywords.map{ |v| v.split ':' })
|
|
38
|
+
query.where hashed_queries
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
def text_fields
|
|
42
|
+
@model_decorator.fields.select do |field_name, metadata|
|
|
43
|
+
@model_decorator.index_field_names.include?(field_name) &&
|
|
44
|
+
%w( string text citext ).include?(metadata[:type])
|
|
45
|
+
end.keys
|
|
46
|
+
end
|
|
47
|
+
end
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
class Wallaby::ActiveRecord::ModelOperator::Validator
|
|
2
|
+
def initialize(model_decorator)
|
|
3
|
+
@model_decorator = model_decorator
|
|
4
|
+
end
|
|
5
|
+
|
|
6
|
+
def valid?(resource)
|
|
7
|
+
resource.attributes.each do |field_name, values|
|
|
8
|
+
next unless metadata = @model_decorator.fields[field_name]
|
|
9
|
+
if %w( daterange tsrange tstzrange ).include?(metadata[:type]) &&
|
|
10
|
+
values.try(:any?, &:blank?)
|
|
11
|
+
resource.errors.add field_name, 'required for range data'
|
|
12
|
+
end
|
|
13
|
+
end
|
|
14
|
+
resource.errors.blank?
|
|
15
|
+
end
|
|
16
|
+
end
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
class Wallaby::ActiveRecord::ModelOperator < Wallaby::ModelOperator
|
|
2
|
+
def collection(params, ability)
|
|
3
|
+
query = querier.search params
|
|
4
|
+
query = query.order params[:sort] if params[:sort].present?
|
|
5
|
+
query.accessible_by ability
|
|
6
|
+
end
|
|
7
|
+
|
|
8
|
+
def new(params)
|
|
9
|
+
permitted = permit params rescue {}
|
|
10
|
+
@model_class.new permitted
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
def find(id, params)
|
|
14
|
+
@model_class.find id
|
|
15
|
+
rescue ActiveRecord::RecordNotFound
|
|
16
|
+
fail Wallaby::ResourceNotFound
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
def create(params, ability)
|
|
20
|
+
resource = @model_class.new
|
|
21
|
+
resource.assign_attributes normalize permit(params)
|
|
22
|
+
ensure_attributes_for ability, :create, resource
|
|
23
|
+
resource.save if valid? resource
|
|
24
|
+
[ resource, resource.errors.blank? ]
|
|
25
|
+
rescue ActiveRecord::StatementInvalid => e
|
|
26
|
+
resource.errors.add :base, e.message
|
|
27
|
+
[ resource, false ]
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
def update(resource, params, ability)
|
|
31
|
+
resource.assign_attributes normalize permit(params)
|
|
32
|
+
ensure_attributes_for ability, :update, resource
|
|
33
|
+
resource.save if valid? resource
|
|
34
|
+
[ resource, resource.errors.blank? ]
|
|
35
|
+
rescue ActiveRecord::StatementInvalid => e
|
|
36
|
+
resource.errors.add :base, e.message
|
|
37
|
+
[ resource, false ]
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
def destroy(resource, params)
|
|
41
|
+
resource.destroy
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
protected
|
|
45
|
+
def permit(params)
|
|
46
|
+
params.require(param_key).permit(permitter.simple_field_names << permitter.compound_hashed_fields)
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
def normalize(params)
|
|
50
|
+
normalizer.normalize params
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
def valid?(resource)
|
|
54
|
+
validator.valid? resource
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
def ensure_attributes_for(ability, action, resource)
|
|
58
|
+
return if ability.blank?
|
|
59
|
+
restricted_conditions = ability.attributes_for action, resource
|
|
60
|
+
resource.assign_attributes restricted_conditions
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
def param_key
|
|
64
|
+
@model_class.model_name.param_key
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
def permitter
|
|
68
|
+
@permitter ||= Wallaby::ActiveRecord::ModelOperator::Permitter.new @model_decorator
|
|
69
|
+
end
|
|
70
|
+
|
|
71
|
+
def querier
|
|
72
|
+
@querier ||= Wallaby::ActiveRecord::ModelOperator::Querier.new @model_decorator
|
|
73
|
+
end
|
|
74
|
+
|
|
75
|
+
def normalizer
|
|
76
|
+
@normalizer ||= Wallaby::ActiveRecord::ModelOperator::Normalizer.new @model_decorator
|
|
77
|
+
end
|
|
78
|
+
|
|
79
|
+
def validator
|
|
80
|
+
@validator ||= Wallaby::ActiveRecord::ModelOperator::Validator.new @model_decorator
|
|
81
|
+
end
|
|
82
|
+
end
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
class Wallaby::ResourceDecorator
|
|
2
|
+
class << self
|
|
3
|
+
def model_class
|
|
4
|
+
if self < Wallaby::ResourceDecorator
|
|
5
|
+
@model_class ||= Wallaby::Utils.to_model_class name.gsub('Decorator', ''), name
|
|
6
|
+
end
|
|
7
|
+
end
|
|
8
|
+
|
|
9
|
+
def model_decorator
|
|
10
|
+
if self < Wallaby::ResourceDecorator
|
|
11
|
+
@model_decorator ||= Wallaby::DecoratorFinder.new_model model_class
|
|
12
|
+
end
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
def decorate(resource)
|
|
16
|
+
return resource if resource.is_a? Wallaby::ResourceDecorator
|
|
17
|
+
new resource
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
delegate *begin
|
|
21
|
+
Wallaby::ModelDecorator.instance_methods \
|
|
22
|
+
- Object.instance_methods - %i( model_class )
|
|
23
|
+
end, to: :model_decorator, allow_nil: true
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
def initialize(resource)
|
|
27
|
+
@resource = resource
|
|
28
|
+
@model_decorator = self.class.model_decorator || Wallaby::DecoratorFinder.new_model(model_class)
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
def method_missing(method_id, *args)
|
|
32
|
+
if @resource.respond_to? method_id
|
|
33
|
+
@resource.public_send method_id, *args
|
|
34
|
+
else
|
|
35
|
+
super
|
|
36
|
+
end
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
delegate :to_s, :to_param, :to_params, to: :@resource
|
|
40
|
+
delegate *begin
|
|
41
|
+
Wallaby::ModelDecorator.instance_methods \
|
|
42
|
+
- %i( index_fields index_field_names show_fields show_field_names form_fields form_field_names ) \
|
|
43
|
+
- Object.instance_methods
|
|
44
|
+
end, to: :@model_decorator
|
|
45
|
+
attr_reader :model_decorator
|
|
46
|
+
|
|
47
|
+
def model_class
|
|
48
|
+
@resource.class
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
def resource
|
|
52
|
+
@resource
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
def to_label
|
|
56
|
+
@model_decorator.guess_title(@resource) || primary_key_value
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
def errors
|
|
60
|
+
@model_decorator.form_active_errors(@resource)
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
def primary_key_value
|
|
64
|
+
@resource.public_send primary_key
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
[ '', 'index_', 'show_', 'form_' ].each do |prefix|
|
|
68
|
+
class_eval <<-RUBY
|
|
69
|
+
def #{ prefix }fields
|
|
70
|
+
@#{ prefix }fields ||= @model_decorator.#{ prefix }fields.dup.freeze
|
|
71
|
+
end
|
|
72
|
+
|
|
73
|
+
def #{ prefix }field_names
|
|
74
|
+
@#{ prefix }field_names ||= @model_decorator.#{ prefix }field_names.dup.freeze
|
|
75
|
+
end
|
|
76
|
+
RUBY
|
|
77
|
+
end
|
|
78
|
+
end
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
class Wallaby::FormBuilder < ActionView::Helpers::FormBuilder
|
|
2
|
+
def error_class(field_name)
|
|
3
|
+
'has-error' if has_error? field_name
|
|
4
|
+
end
|
|
5
|
+
|
|
6
|
+
def error_messages(field_name)
|
|
7
|
+
errors = Array object.errors[ field_name ]
|
|
8
|
+
return if errors.blank?
|
|
9
|
+
|
|
10
|
+
content_tag :ul, class: 'text-danger' do
|
|
11
|
+
errors.each do |message|
|
|
12
|
+
concat content_tag :li, content_tag(:small, raw(message))
|
|
13
|
+
end
|
|
14
|
+
end
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
protected
|
|
18
|
+
def method_missing(method, *args, &block)
|
|
19
|
+
if @template.respond_to? method
|
|
20
|
+
self.class.delegate method, to: :@template
|
|
21
|
+
@template.public_send method, *args, &block
|
|
22
|
+
else
|
|
23
|
+
super
|
|
24
|
+
end
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
def has_error?(field_name)
|
|
28
|
+
object.errors[field_name].present?
|
|
29
|
+
end
|
|
30
|
+
end
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
require 'erubis'
|
|
2
|
+
|
|
3
|
+
# TODO: move this kind of logic into a gem called faster rails :)
|
|
4
|
+
class Wallaby::CachedCompiledErb < ActionView::Template::Handlers::ERB
|
|
5
|
+
def call(template)
|
|
6
|
+
if Rails.env.development?
|
|
7
|
+
super
|
|
8
|
+
else
|
|
9
|
+
Rails.cache.fetch "wallaby/views/erb/#{ template.inspect }" do
|
|
10
|
+
super
|
|
11
|
+
end
|
|
12
|
+
end
|
|
13
|
+
end
|
|
14
|
+
end
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
module Wallaby::ApplicationHelper
|
|
2
|
+
def clean_params
|
|
3
|
+
params.except :resources, :action
|
|
4
|
+
end
|
|
5
|
+
|
|
6
|
+
# override `actionview/lib/action_view/routing_url_for.rb#url_for`
|
|
7
|
+
def url_for(options = nil)
|
|
8
|
+
if options.is_a?(Hash) && options.slice(:action, :resources).length == 2
|
|
9
|
+
return wallaby_resourceful_url_for options
|
|
10
|
+
end
|
|
11
|
+
super
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
def wallaby_resourceful_url_for(options = {})
|
|
15
|
+
# DEPRECATION WARNING: You are calling a `*_path` helper with the `only_path` option explicitly set to `false`. This option will stop working on path helpers in Rails 5. Use the corresponding `*_url` helper instead.
|
|
16
|
+
options = options.except :only_path
|
|
17
|
+
case options[:action]
|
|
18
|
+
when 'index', 'create'
|
|
19
|
+
wallaby_engine.resources_path options
|
|
20
|
+
when 'new'
|
|
21
|
+
wallaby_engine.new_resource_path options
|
|
22
|
+
when 'edit'
|
|
23
|
+
wallaby_engine.edit_resource_path options
|
|
24
|
+
when 'show', 'update', 'destroy'
|
|
25
|
+
wallaby_engine.resource_path options
|
|
26
|
+
else
|
|
27
|
+
wallaby_engine.url_for options
|
|
28
|
+
end
|
|
29
|
+
end
|
|
30
|
+
end
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
require 'securerandom'
|
|
2
|
+
|
|
3
|
+
# NOTE: Global helper methods should go in here
|
|
4
|
+
module Wallaby::CoreHelper
|
|
5
|
+
include Wallaby::StylingHelper
|
|
6
|
+
include Wallaby::LinksHelper
|
|
7
|
+
|
|
8
|
+
def to_model_label(model_class)
|
|
9
|
+
Wallaby::Utils.to_model_label model_class
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
def to_resources_name(model_class)
|
|
13
|
+
Wallaby::Utils.to_resources_name model_class
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
def current_model_label
|
|
17
|
+
if current_resources_name.present?
|
|
18
|
+
label = to_model_label current_resources_name
|
|
19
|
+
return "Resource: #{ label }" if label.present?
|
|
20
|
+
end
|
|
21
|
+
'Resources'
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
def body_class
|
|
25
|
+
[
|
|
26
|
+
params[:action],
|
|
27
|
+
current_resources_name.try(:gsub, '::', '__'),
|
|
28
|
+
content_for(:custom_body_class)
|
|
29
|
+
].compact.join ' '
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
def page_title
|
|
33
|
+
'Wallaby::Admin'
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
def ct(key, options = {})
|
|
37
|
+
t key, { raise: true }.merge(options)
|
|
38
|
+
rescue I18n::MissingTranslationData => e
|
|
39
|
+
keys = I18n.normalize_keys(e.locale, e.key, e.options[:scope])
|
|
40
|
+
keys.last.to_s.titleize
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
def random_uuid
|
|
44
|
+
SecureRandom.uuid
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
def model_classes
|
|
48
|
+
Wallaby::Map.model_classes.sort_by &:name
|
|
49
|
+
end
|
|
50
|
+
end
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
module Wallaby::FormHelper
|
|
2
|
+
def form_type_partial_render(options = {}, locals = {}, &block)
|
|
3
|
+
form = locals[:form]
|
|
4
|
+
field_name = locals[:field_name].to_s
|
|
5
|
+
|
|
6
|
+
fail ArgumentError unless form.present? && field_name.present? && form.object.is_a?(Wallaby::ResourceDecorator)
|
|
7
|
+
|
|
8
|
+
locals[:object] = object = form.object
|
|
9
|
+
locals[:metadata] = object.form_metadata_of locals[:field_name]
|
|
10
|
+
locals[:value] = object.public_send locals[:field_name]
|
|
11
|
+
|
|
12
|
+
render(options, locals, &block) or render('string', locals, &block)
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
def model_choices(model_decorator)
|
|
16
|
+
collection = model_servicer(model_decorator).collection Hash.new, current_ability
|
|
17
|
+
decorate(collection).map do |decorated|
|
|
18
|
+
[ decorated.to_label, decorated.primary_key_value ]
|
|
19
|
+
end
|
|
20
|
+
end
|
|
21
|
+
end
|