wallaby 5.1.5 → 5.1.6

Sign up to get free protection for your applications and to get access to all the features.
Files changed (72) hide show
  1. checksums.yaml +4 -4
  2. data/Rakefile +1 -1
  3. data/app/controllers/wallaby/abstract_resources_controller.rb +171 -187
  4. data/app/controllers/wallaby/application_controller.rb +15 -4
  5. data/app/controllers/wallaby/base_controller.rb +1 -3
  6. data/app/controllers/wallaby/secure_controller.rb +10 -6
  7. data/app/security/ability.rb +1 -0
  8. data/app/views/wallaby/resources/form/_float.html.erb +1 -1
  9. data/config/locales/wallaby.en.yml +5 -0
  10. data/lib/adaptors/wallaby/active_record.rb +1 -1
  11. data/lib/adaptors/wallaby/active_record/model_decorator.rb +17 -19
  12. data/lib/adaptors/wallaby/active_record/model_decorator/fields_builder.rb +7 -0
  13. data/lib/adaptors/wallaby/active_record/model_decorator/fields_builder/association_builder.rb +11 -0
  14. data/lib/adaptors/wallaby/active_record/model_decorator/fields_builder/polymorphic_builder.rb +10 -1
  15. data/lib/adaptors/wallaby/active_record/model_decorator/fields_builder/sti_builder.rb +14 -7
  16. data/lib/adaptors/wallaby/active_record/model_decorator/title_field_finder.rb +4 -0
  17. data/lib/adaptors/wallaby/active_record/model_finder.rb +4 -3
  18. data/lib/adaptors/wallaby/active_record/model_pagination_provider.rb +3 -6
  19. data/lib/adaptors/wallaby/active_record/model_service_provider.rb +12 -3
  20. data/lib/adaptors/wallaby/active_record/model_service_provider/normalizer.rb +16 -1
  21. data/lib/adaptors/wallaby/active_record/model_service_provider/permitter.rb +14 -2
  22. data/lib/adaptors/wallaby/active_record/model_service_provider/querier.rb +46 -1
  23. data/lib/adaptors/wallaby/active_record/model_service_provider/querier/transformer.rb +11 -5
  24. data/lib/adaptors/wallaby/active_record/model_service_provider/validator.rb +6 -0
  25. data/lib/concerns/wallaby/resources_helper_methods.rb +44 -0
  26. data/lib/decorators/wallaby/abstract_resource_decorator.rb +9 -4
  27. data/lib/errors/wallaby/model_not_found.rb +1 -0
  28. data/lib/errors/wallaby/resource_not_found.rb +1 -0
  29. data/lib/forms/wallaby/form_builder.rb +5 -3
  30. data/lib/helpers/wallaby/application_helper.rb +10 -1
  31. data/lib/helpers/wallaby/base_helper.rb +12 -4
  32. data/lib/helpers/wallaby/form_helper.rb +7 -4
  33. data/lib/helpers/wallaby/links_helper.rb +10 -7
  34. data/lib/helpers/wallaby/resources_helper.rb +2 -0
  35. data/lib/helpers/wallaby/secure_helper.rb +13 -7
  36. data/lib/helpers/wallaby/styling_helper.rb +1 -1
  37. data/lib/interfaces/wallaby/mode.rb +38 -16
  38. data/lib/interfaces/wallaby/model_decorator.rb +36 -27
  39. data/lib/interfaces/wallaby/model_decorator/field_helpers.rb +12 -2
  40. data/lib/interfaces/wallaby/model_finder.rb +1 -0
  41. data/lib/interfaces/wallaby/model_pagination_provider.rb +6 -5
  42. data/lib/interfaces/wallaby/model_service_provider.rb +10 -2
  43. data/lib/paginators/wallaby/abstract_resource_paginator.rb +6 -1
  44. data/lib/parsers/wallaby/parser.rb +1 -0
  45. data/lib/responders/wallaby/abstract_responder.rb +15 -2
  46. data/lib/routes/wallaby/resources_router.rb +4 -0
  47. data/lib/servicers/wallaby/abstract_model_servicer.rb +25 -1
  48. data/lib/servicers/wallaby/model_servicer.rb +1 -0
  49. data/lib/services/wallaby/link_options_normalizer.rb +13 -9
  50. data/lib/services/wallaby/lookup_context_wrapper.rb +11 -2
  51. data/lib/services/wallaby/map.rb +107 -69
  52. data/lib/services/wallaby/map/mode_mapper.rb +2 -0
  53. data/lib/services/wallaby/map/model_class_collector.rb +7 -0
  54. data/lib/services/wallaby/map/model_class_mapper.rb +15 -7
  55. data/lib/services/wallaby/partial_renderer.rb +7 -0
  56. data/lib/services/wallaby/prefixes_builder.rb +18 -0
  57. data/lib/services/wallaby/sorting/hash_builder.rb +7 -1
  58. data/lib/services/wallaby/sorting/link_builder.rb +6 -1
  59. data/lib/services/wallaby/sorting/next_builder.rb +23 -2
  60. data/lib/tree/wallaby/node.rb +2 -0
  61. data/lib/utils/wallaby/test_utils.rb +32 -0
  62. data/lib/utils/wallaby/utils.rb +51 -5
  63. data/lib/wallaby.rb +1 -0
  64. data/lib/wallaby/configuration.rb +9 -3
  65. data/lib/wallaby/configuration/features.rb +2 -1
  66. data/lib/wallaby/configuration/mapping.rb +66 -0
  67. data/lib/wallaby/configuration/metadata.rb +1 -0
  68. data/lib/wallaby/configuration/pagination.rb +2 -1
  69. data/lib/wallaby/engine.rb +4 -0
  70. data/lib/wallaby/version.rb +1 -1
  71. metadata +5 -3
  72. data/lib/tasks/wallaby_tasks.rake +0 -4
@@ -16,20 +16,33 @@ module Wallaby
16
16
  layout 'wallaby/application'
17
17
 
18
18
  # Not found page
19
+ # @param exception [Exception]
19
20
  def not_found(exception = nil)
20
21
  error_rendering(exception, __callee__)
21
22
  end
22
23
 
23
24
  # Bad request page
25
+ # @param exception [Exception]
24
26
  def bad_request(exception = nil)
25
27
  error_rendering(exception, __callee__)
26
28
  end
27
29
 
28
30
  # Unprocessable entity page
31
+ # @param exception [Exception]
29
32
  def unprocessable_entity(exception = nil)
30
33
  error_rendering(exception, __callee__)
31
34
  end
32
35
 
36
+ # @return [Wallaby::Configuration] global configuration
37
+ def self.configuration
38
+ ::Wallaby.configuration
39
+ end
40
+
41
+ # @return [Wallaby::Configuration] global configuration
42
+ def configuration
43
+ self.class.configuration
44
+ end
45
+
33
46
  protected
34
47
 
35
48
  # @see https://github.com/rails/rails/blob/5-0-stable/actionpack/lib/action_controller/metal/helpers.rb#L118
@@ -38,11 +51,9 @@ module Wallaby
38
51
  @helpers ||= defined?(super) ? super : view_context
39
52
  end
40
53
 
41
- def configuration
42
- ::Wallaby.configuration
43
- end
44
-
45
54
  # capture exceptions and display the error using error layout and view
55
+ # @param exception [Exception]
56
+ # @param symbol [Symbol] http status symbol
46
57
  def error_rendering(exception, symbol)
47
58
  @exception = exception
48
59
  @symbol = symbol
@@ -8,13 +8,11 @@ module Wallaby
8
8
 
9
9
  before_action :authenticate_user!, except: [:status]
10
10
 
11
- # health check
11
+ # Health check page
12
12
  def healthy
13
13
  render plain: 'healthy'
14
14
  end
15
15
 
16
- protected
17
-
18
16
  # @return [String] the resources name coming from params
19
17
  def current_resources_name
20
18
  @current_resources_name ||= params[:resources]
@@ -8,22 +8,23 @@ module Wallaby
8
8
  rescue_from ::CanCan::AccessDenied, with: :forbidden
9
9
 
10
10
  # Unauthorized page
11
+ # @param exception [Exception]
11
12
  def unauthorized(exception = nil)
12
13
  error_rendering(exception, __callee__)
13
14
  end
14
15
 
15
16
  # Forbidden page
17
+ # @param exception [Exception]
16
18
  def forbidden(exception = nil)
17
19
  error_rendering(exception, __callee__)
18
20
  end
19
21
 
20
- protected
21
-
22
22
  # Precedence of current_user:
23
23
  # - [Security] @see Wallaby::SecureController#security_config
24
24
  # - super
25
25
  # - do nothing
26
26
  # @see Devise::Controllers::Helpers#define_helpers
27
+ # @return a user object
27
28
  def current_user
28
29
  @current_user ||=
29
30
  if security_config.current_user? || !defined? super
@@ -33,6 +34,13 @@ module Wallaby
33
34
  end
34
35
  end
35
36
 
37
+ # @return [Wallaby::Configuration::Security] security configuration
38
+ def security_config
39
+ configuration.security
40
+ end
41
+
42
+ protected
43
+
36
44
  # Precedence of authenticate_user!:
37
45
  # - [Security] @see Wallaby::SecureController#security_config
38
46
  # - super
@@ -48,9 +56,5 @@ module Wallaby
48
56
  raise NotAuthenticated unless authenticated
49
57
  true
50
58
  end
51
-
52
- def security_config
53
- configuration.security
54
- end
55
59
  end
56
60
  end
@@ -1,3 +1,4 @@
1
+ # @private
1
2
  # Defualt ability for wallaby
2
3
  # If main app has defined `ability.rb`, this file will not be loaded/used.
3
4
  class Ability
@@ -11,7 +11,7 @@ The following params are the variables that can be used in this partial.
11
11
  <%= form.label field_name, metadata[:label] %>
12
12
  <div class="row">
13
13
  <div class="col-xs-6 col-sm-4">
14
- <%= form.number_field field_name, class: 'form-control' %>
14
+ <%= form.number_field field_name, class: 'form-control', options: metadata[:options] || { step: 0.1 } %>
15
15
  </div>
16
16
  </div>
17
17
  <%= form.error_messages field_name %>
@@ -94,3 +94,8 @@ en:
94
94
  macaddr_html: 'Example: <code>08:00:2b:01:02:03</code> which stores MAC addresses.'
95
95
  path_html: 'Format: <code>((x1, y1) , ... , (xn, yn))</code> where the points are the end points of the line segments comprising the path.'
96
96
  polygon_html: 'Format: <code>((x1, y1) , ... , (xn, yn))</code> where the points are the end points of the line segments comprising the boundary of the polygon.'
97
+
98
+ wallaby:
99
+ map:
100
+ model_class_mapper:
101
+ missing_model_class: "[WALLABY] Please define self.model_class for %{model} or set it as global.\n @see Wallaby.configuration.mapping"
@@ -1,5 +1,5 @@
1
1
  module Wallaby
2
- # Active Record mode
2
+ # ActiveRecord mode
3
3
  class ActiveRecord < Mode
4
4
  end
5
5
  end
@@ -1,6 +1,6 @@
1
1
  module Wallaby
2
2
  class ActiveRecord
3
- # Modal decorator for Active Record
3
+ # Modal decorator for ActiveRecord
4
4
  class ModelDecorator < ::Wallaby::ModelDecorator
5
5
  # Data types to exclude for index page
6
6
  INDEX_EXCLUSIVE_DATA_TYPES =
@@ -9,9 +9,9 @@ module Wallaby
9
9
  # Data types to exclude for form page
10
10
  FORM_EXCLUSIVE_DATA_TYPES = %w(created_at updated_at).freeze
11
11
 
12
- # Origin metadata coming from data source.
12
+ # Origin metadata directly coming from ActiveRecord.
13
13
  # It needs to be frozen so that we can keep the metadata integrity
14
- # @return [Hash]
14
+ # @return [Hash] metadata
15
15
  # example:
16
16
  # {
17
17
  # # general field
@@ -30,7 +30,7 @@ module Wallaby
30
30
  # }
31
31
  def fields
32
32
  @fields ||= ::ActiveSupport::HashWithIndifferentAccess.new.tap do |hash|
33
- # NOTE: There is a chance that people create Active Record class
33
+ # NOTE: There is a chance that people create ActiveRecord class
34
34
  # before they do the migration, so initialising the fields will raise
35
35
  # all kinds of error. Therefore, we need to check the table existence
36
36
  if @model_class.table_exists?
@@ -41,26 +41,25 @@ module Wallaby
41
41
  end.freeze
42
42
  end
43
43
 
44
- # A copy of all the fields for index page
45
- # @return [Hash]
44
+ # A copy of `fields` for index page
45
+ # @return [Hash] metadata
46
46
  def index_fields
47
47
  @index_fields ||= Utils.clone fields
48
48
  end
49
49
 
50
- # A copy of all the fields for show page
51
- # @return [Hash]
50
+ # A copy of `fields` for show page
51
+ # @return [Hash] metadata
52
52
  def show_fields
53
53
  @show_fields ||= Utils.clone fields
54
54
  end
55
55
 
56
- # A copy of all the fields for form page
57
- # @return [Hash]
56
+ # A copy of `fields` for form (new/edit) page
57
+ # @return [Hash] metadata
58
58
  def form_fields
59
59
  @form_fields ||= Utils.clone fields
60
60
  end
61
61
 
62
- # Fields name for index page
63
- # @return [Array]
62
+ # @return [Array<String>] a list of field names for index page
64
63
  def index_field_names
65
64
  @index_field_names ||= begin
66
65
  index_fields.reject do |_field_name, metadata|
@@ -70,8 +69,7 @@ module Wallaby
70
69
  end
71
70
  end
72
71
 
73
- # Fields name for form page
74
- # @return [Array]
72
+ # @return [Array<String>] a list of field names for form (new/edit) page
75
73
  def form_field_names
76
74
  @form_field_names ||= begin
77
75
  form_fields.reject do |field_name, metadata|
@@ -82,22 +80,22 @@ module Wallaby
82
80
  end
83
81
  end
84
82
 
85
- # Errors for resource
86
- # @return [ActiveModel::Errors]
83
+ # @return [ActiveModel::Errors] errors for resource
87
84
  def form_active_errors(resource)
88
85
  resource.errors
89
86
  end
90
87
 
91
- # Primary key for the resource
92
- # @return [String]
88
+ # @return [String] primary key for the resource
93
89
  def primary_key
94
90
  @model_class.primary_key
95
91
  end
96
92
 
97
93
  # To guess the title for resource.
94
+ #
98
95
  # It will go through the fields and try to find out the one that looks
99
96
  # like a name or text to represent this resource. Otherwise, it will fall
100
97
  # back to primary key.
98
+ #
101
99
  # @param resource [Object]
102
100
  # @return [String] the title of given resource
103
101
  def guess_title(resource)
@@ -121,7 +119,7 @@ module Wallaby
121
119
 
122
120
  # Find out all the foreign keys for a list of fields
123
121
  # @param fields [Hash] metadata of fields
124
- # @return [Array] a list of foreign keys
122
+ # @return [Array<String>] a list of foreign keys
125
123
  def foreign_keys_from_associations(fields = association_fields)
126
124
  fields.each_with_object([]) do |(_field_name, metadata), keys|
127
125
  keys << metadata[:foreign_key] if metadata[:foreign_key]
@@ -1,12 +1,15 @@
1
1
  module Wallaby
2
2
  class ActiveRecord
3
3
  class ModelDecorator
4
+ # @private
4
5
  # To search and build the metadata for fields
5
6
  class FieldsBuilder
7
+ # @param model_class [Class] model class
6
8
  def initialize(model_class)
7
9
  @model_class = model_class
8
10
  end
9
11
 
12
+ # @return [Hash<String, Hash>] a hash for general fields
10
13
  def general_fields
11
14
  @model_class.columns.each_with_object({}) do |column, fields|
12
15
  metadata = {
@@ -19,6 +22,7 @@ module Wallaby
19
22
  end
20
23
  end
21
24
 
25
+ # @return [Hash<String, Hash>] a hash for general fields
22
26
  def association_fields
23
27
  @model_class.reflections.each_with_object({}) do |(name, ref), fields|
24
28
  metadata = {
@@ -33,14 +37,17 @@ module Wallaby
33
37
 
34
38
  protected
35
39
 
40
+ # @see Wallaby::ActiveRecord::ModelDecorator::StiBuilder
36
41
  def sti_builder
37
42
  @sti_builder ||= StiBuilder.new(@model_class)
38
43
  end
39
44
 
45
+ # @see Wallaby::ActiveRecord::ModelDecorator::AssociationBuilder
40
46
  def association_builder
41
47
  @association_builder ||= AssociationBuilder.new
42
48
  end
43
49
 
50
+ # @see Wallaby::ActiveRecord::ModelDecorator::PolymorphicBuilder
44
51
  def polymorphic_builder
45
52
  @polymorphic_builder ||= PolymorphicBuilder.new
46
53
  end
@@ -2,8 +2,12 @@ module Wallaby
2
2
  class ActiveRecord
3
3
  class ModelDecorator
4
4
  class FieldsBuilder
5
+ # @private
5
6
  # To build the metadata for associations
6
7
  class AssociationBuilder
8
+ # Update the metadata
9
+ # @param metadata [Hash]
10
+ # @param reflection [ActiveRecord::Reflection]
7
11
  def update(metadata, reflection)
8
12
  type = reflection.macro
9
13
  metadata[:is_association] = true
@@ -14,6 +18,9 @@ module Wallaby
14
18
 
15
19
  private
16
20
 
21
+ # @param reflection [ActiveRecord::Reflection]
22
+ # @param type [Symbol]
23
+ # @return [String] foreign key
17
24
  def foreign_key_for(reflection, type)
18
25
  if type == :belongs_to || reflection.polymorphic?
19
26
  reflection.foreign_key
@@ -25,10 +32,14 @@ module Wallaby
25
32
  end
26
33
  end
27
34
 
35
+ # @param reflection [ActiveRecord::Reflection]
36
+ # @return [Boolean] whether it's a through relation
28
37
  def through?(reflection)
29
38
  reflection.is_a? ::ActiveRecord::Reflection::ThroughReflection
30
39
  end
31
40
 
41
+ # @param reflection [ActiveRecord::Reflection]
42
+ # @return [Boolean] whether it has scope
32
43
  def scope?(reflection)
33
44
  reflection.scope.present?
34
45
  end
@@ -2,8 +2,12 @@ module Wallaby
2
2
  class ActiveRecord
3
3
  class ModelDecorator
4
4
  class FieldsBuilder
5
+ # @private
5
6
  # To build the metadata for polymorphic
6
7
  class PolymorphicBuilder
8
+ # update the metadata
9
+ # @param metadata [Hash]
10
+ # @param reflection [ActiveRecord::Reflection]
7
11
  def update(metadata, reflection)
8
12
  if reflection.polymorphic?
9
13
  metadata[:is_polymorphic] = true
@@ -16,21 +20,26 @@ module Wallaby
16
20
 
17
21
  private
18
22
 
23
+ # @param reflection [ActiveRecord::Reflection]
24
+ # @return [Array<Class>] a list of classes for this polymorphism
19
25
  def polymorphic_list_for(reflection)
20
26
  all_model_class.each_with_object([]) do |model_class, list|
21
- # TODO: need to check the class as well
22
27
  if polymorphic_defined? model_class, reflection.name
23
28
  list << model_class
24
29
  end
25
30
  end
26
31
  end
27
32
 
33
+ # @return [Array<Class>] a list of all ActiveRecord classes
28
34
  def all_model_class
29
35
  Map
30
36
  .mode_map
31
37
  .select { |_, mode| mode == ::Wallaby::ActiveRecord }.keys
32
38
  end
33
39
 
40
+ # @param model_class [Class] model class
41
+ # @param polymorphic_name [String] polymorphic name
42
+ # @return [Boolean] if polymorphism defined?
34
43
  def polymorphic_defined?(model_class, polymorphic_name)
35
44
  polymorphic_name_sym = polymorphic_name.try(:to_sym)
36
45
  model_class.reflections.any? do |_field_name, reflection|
@@ -2,12 +2,17 @@ module Wallaby
2
2
  class ActiveRecord
3
3
  class ModelDecorator
4
4
  class FieldsBuilder
5
+ # @private
5
6
  # To build the metadata for sti column
6
7
  class StiBuilder
8
+ # @param model_class [Class] model class
7
9
  def initialize(model_class)
8
10
  @model_class = model_class
9
11
  end
10
12
 
13
+ # update the metadata
14
+ # @param metadata [Hash]
15
+ # @param column [ActiveRecord::ConnectionAdapters::Column]
11
16
  def update(metadata, column)
12
17
  return unless @model_class.inheritance_column == column.name
13
18
  metadata[:type] = 'sti'.freeze
@@ -16,21 +21,23 @@ module Wallaby
16
21
 
17
22
  private
18
23
 
24
+ # @param klass [Class]
25
+ # @return [Array<Class>] a list of STI classes for this model
19
26
  def sti_list(klass)
20
- list = klass
21
- .descendants
22
- .each_with_object([klass]) do |child, result|
23
- result << child
24
- end
27
+ list = klass.descendants << klass
25
28
  list.sort_by(&:name)
26
29
  end
27
30
 
28
- def find_parent_of(model_class)
29
- parent = model_class
31
+ # @param klass [Class]
32
+ # @return [Class] the top parent class in the STI hierarchy
33
+ def find_parent_of(klass)
34
+ parent = klass
30
35
  parent = parent.superclass until top_parent?(parent.superclass)
31
36
  parent
32
37
  end
33
38
 
39
+ # @param klass [Class]
40
+ # @return [Boolean] whether the class is ActiveRecord base class
34
41
  def top_parent?(klass)
35
42
  klass == ModelFinder.base ||
36
43
  klass.respond_to?(:abstract_class?) && klass.abstract_class?
@@ -1,16 +1,20 @@
1
1
  module Wallaby
2
2
  class ActiveRecord
3
3
  class ModelDecorator
4
+ # @private
4
5
  # Try to find the field that can be used as title
5
6
  class TitleFieldFinder
6
7
  TITLE_FIELD_TYPES = %w(string).freeze
7
8
  TITLE_NAMES = %w(name title string text).freeze
8
9
 
10
+ # @param model_class [Class] model class
11
+ # @param fields [Hash] fields metadata
9
12
  def initialize(model_class, fields)
10
13
  @model_class = model_class
11
14
  @fields = fields
12
15
  end
13
16
 
17
+ # @return [String] field name that can be used as title
14
18
  def find
15
19
  possible_title_fields = @fields.select do |_field_name, metadata|
16
20
  TITLE_FIELD_TYPES.include? metadata[:type]