wallaby 4.1.6
Sign up to get free protection for your applications and to get access to all the features.
- 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
|