snfoil-rails 0.1.0 → 0.3.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (31) hide show
  1. checksums.yaml +4 -4
  2. data/CODE_OF_CONDUCT.md +74 -0
  3. data/Rakefile +1 -1
  4. data/lib/generators/sn_foil/sn_foil_generator.rb +47 -0
  5. data/lib/sn_foil/controller/api.rb +77 -0
  6. data/lib/sn_foil/controller/base.rb +19 -0
  7. data/lib/sn_foil/controller/concerns/change_controller_concern.rb +21 -0
  8. data/lib/sn_foil/controller/concerns/create_controller_concern.rb +38 -0
  9. data/lib/sn_foil/controller/concerns/destroy_controller_concern.rb +40 -0
  10. data/lib/sn_foil/controller/concerns/index_controller_concern.rb +66 -0
  11. data/lib/sn_foil/controller/concerns/setup_controller_concern.rb +84 -0
  12. data/lib/sn_foil/controller/concerns/show_controller_concern.rb +36 -0
  13. data/lib/sn_foil/controller/concerns/update_controller_concern.rb +38 -0
  14. data/lib/sn_foil/jsonapi_deserializer.rb +151 -0
  15. data/lib/sn_foil/jsonapi_serializer.rb +16 -0
  16. data/lib/sn_foil/rails.rb +18 -7
  17. data/lib/sn_foil/rails/engine.rb +24 -0
  18. data/lib/sn_foil/rails/version.rb +1 -1
  19. data/lib/sn_foil/searcher.rb +123 -0
  20. metadata +47 -13
  21. data/lib/sn_foil/rails/controller/api.rb +0 -22
  22. data/lib/sn_foil/rails/controller/concerns/change_controller_concern.rb +0 -28
  23. data/lib/sn_foil/rails/controller/concerns/create_controller_concern.rb +0 -40
  24. data/lib/sn_foil/rails/controller/concerns/destroy_controller_concern.rb +0 -42
  25. data/lib/sn_foil/rails/controller/concerns/index_controller_concern.rb +0 -72
  26. data/lib/sn_foil/rails/controller/concerns/setup_controller_concern.rb +0 -110
  27. data/lib/sn_foil/rails/controller/concerns/show_controller_concern.rb +0 -38
  28. data/lib/sn_foil/rails/controller/concerns/update_controller_concern.rb +0 -40
  29. data/lib/sn_foil/rails/railtie.rb +0 -10
  30. data/lib/sn_foil/rails/searcher.rb +0 -127
  31. data/lib/tasks/sn_foil/rails_tasks.rake +0 -5
@@ -1,22 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require 'action_controller/api'
4
- require_relative 'concerns/create_controller_concern'
5
- require_relative 'concerns/destroy_controller_concern'
6
- require_relative 'concerns/index_controller_concern'
7
- require_relative 'concerns/show_controller_concern'
8
- require_relative 'concerns/update_controller_concern'
9
-
10
- module SnFoil
11
- module Rails
12
- module Controller
13
- class API < ::ActionController::API
14
- include Concerns::CreateControllerConcern
15
- include Concerns::DestroyControllerConcern
16
- include Concerns::IndexControllerConcern
17
- include Concerns::ShowControllerConcern
18
- include Concerns::UpdateControllerConcern
19
- end
20
- end
21
- end
22
- end
@@ -1,28 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require 'active_support/concern'
4
- require_relative 'setup_controller_concern'
5
-
6
- module SnFoil
7
- module Rails
8
- module Controller
9
- module Concerns
10
- module ChangeControllerConcern
11
- extend ActiveSupport::Concern
12
-
13
- included do
14
- include SetupControllerConcern
15
- end
16
-
17
- def render_change(model, **_options)
18
- if model.errors.empty?
19
- render model
20
- else
21
- render model.errors, status: :unprocessable_entity
22
- end
23
- end
24
- end
25
- end
26
- end
27
- end
28
- end
@@ -1,40 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require 'active_support/concern'
4
- require_relative 'setup_controller_concern'
5
- require_relative 'change_controller_concern'
6
-
7
- module SnFoil
8
- module Rails
9
- module Controller
10
- module Concerns
11
- module CreateControllerConcern
12
- extend ActiveSupport::Concern
13
-
14
- included do
15
- include SetupControllerConcern
16
- include ChangeControllerConcern
17
- end
18
-
19
- def create(**options)
20
- options = setup_create(**options)
21
- model = process_create(**options)
22
- render_create(model, **options)
23
- end
24
-
25
- def setup_create(**options)
26
- setup_options(**options.merge(deserialize: true))
27
- end
28
-
29
- def process_create(**options)
30
- current_context(**options).create(**options)
31
- end
32
-
33
- def render_create(model, **options)
34
- render_change(model, **options)
35
- end
36
- end
37
- end
38
- end
39
- end
40
- end
@@ -1,42 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require 'active_support/concern'
4
- require_relative 'setup_controller_concern'
5
-
6
- module SnFoil
7
- module Rails
8
- module Controller
9
- module Concerns
10
- module DestroyControllerConcern
11
- extend ActiveSupport::Concern
12
-
13
- included do
14
- include SetupControllerConcern
15
- end
16
-
17
- def destroy(**options)
18
- options = setup_update(**options)
19
- model = process_destroy(**options)
20
- render_destroy(model, **options)
21
- end
22
-
23
- def setup_destroy(**options)
24
- setup_options(**options)
25
- end
26
-
27
- def process_destroy(**options)
28
- current_context(**options).destroy(**options)
29
- end
30
-
31
- def render_destroy(model, **_options)
32
- if model.errors.empty?
33
- render nil
34
- else
35
- render model.errors, status: :unprocessable_entity
36
- end
37
- end
38
- end
39
- end
40
- end
41
- end
42
- end
@@ -1,72 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require 'active_support/concern'
4
- require_relative 'setup_controller_concern'
5
-
6
- module SnFoil
7
- module Rails
8
- module Controller
9
- module Concerns
10
- module IndexControllerConcern
11
- extend ActiveSupport::Concern
12
-
13
- included do
14
- include SetupControllerConcern
15
- end
16
-
17
- def index(**options)
18
- options = setup_index(**options)
19
- results = process_index(**options)
20
- render_index(results, **options)
21
- end
22
-
23
- def setup_index(**options)
24
- setup_options(**options)
25
- end
26
-
27
- def process_index(**options)
28
- searcher = options.fetch(:searcher) do
29
- current_context(**options).index(options)
30
- end
31
- searcher.results
32
- end
33
-
34
- def render_index(results, **options)
35
- paginate(results, **options)
36
- end
37
-
38
- def paginate(results, **options)
39
- return results unless results.respond_to?(:page)
40
-
41
- results.page(page(**options))
42
- .per(per_page(**options))
43
- end
44
-
45
- def page(**options)
46
- options[:params].fetch(:page, 1).to_i
47
- end
48
-
49
- def per_page(**options)
50
- per_page_param = options[:params].fetch(:per_page, 10).to_i
51
- return 10_000 if per_page_param.zero?
52
-
53
- per_page_param
54
- end
55
-
56
- def meta(results, **options)
57
- total_pages = results&.total_pages
58
- total_count = results&.total_count
59
- paginated = total_pages && total_count
60
-
61
- {
62
- page: paginated ? page(**options) : nil,
63
- pages: total_pages || 1,
64
- total: total_count || 1,
65
- per: paginated ? per_page(**options) : nil
66
- }
67
- end
68
- end
69
- end
70
- end
71
- end
72
- end
@@ -1,110 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require 'active_support/concern'
4
-
5
- module SnFoil
6
- module Rails
7
- module Controller
8
- module Concerns
9
- module SetupControllerConcern
10
- extend ActiveSupport::Concern
11
-
12
- class_methods do
13
- attr_reader :i_deserializer, :i_serializer, :i_context
14
-
15
- def context(klass = nil)
16
- @i_context = klass
17
- end
18
-
19
- def serializer(klass = nil)
20
- @i_serializer = klass
21
- end
22
-
23
- def deserializer(klass = nil)
24
- @i_deserializer = klass
25
- end
26
- end
27
-
28
- def context(**options)
29
- options[:context] || self.class.i_context
30
- end
31
-
32
- def serializer(**options)
33
- options[:serializer] || self.class.i_serializer
34
- end
35
-
36
- def deserializer(**options)
37
- options[:deserializer] || self.class.i_deserializer
38
- end
39
-
40
- def setup_options(**options)
41
- options = inject_params(**options)
42
- options = inject_id(**options)
43
- options = inject_includes(**options)
44
- options = inject_controller_action(**options)
45
- inject_deserialized_params(**options)
46
- end
47
-
48
- def current_context(**options)
49
- @current_context ||= context(**options).new(context_user)
50
- end
51
-
52
- protected
53
-
54
- def pundit_not_authorized
55
- head :forbidden
56
- end
57
-
58
- private
59
-
60
- # Grab the rails params and inject them into the options
61
- def inject_params(**options)
62
- return options unless params
63
-
64
- options[:params] = params.to_unsafe_h.deep_symbolize_keys
65
- options[:controller_params] = options[:params]
66
- options
67
- end
68
-
69
- def inject_id(**options)
70
- return options if options[:id]
71
-
72
- options[:id] = id if defined? id
73
- options[:id] ||= options[:params][:id]
74
- options
75
- end
76
-
77
- def inject_includes(**options)
78
- return options if options[:include]
79
- return options unless options.dig(:params, :include)
80
-
81
- options[:include] = options.dig(:params, :include)
82
- .split(',')
83
- .map { |item| item.underscore.to_sym }
84
- options
85
- end
86
-
87
- def inject_controller_action(**options)
88
- return options if options[:controller_action]
89
- return options unless options.dig(:params, :action)
90
-
91
- options[:controller_action] = options[:params][:action]
92
- options
93
- end
94
-
95
- def inject_deserialized_params(**options)
96
- return options unless options[:params].present? && options[:deserialize] == true
97
- return options unless deserializer(**options)
98
-
99
- options[:params] = deserializer(**options).new(options[:params], **options).to_h
100
- options
101
- end
102
-
103
- def context_user
104
- return current_user if defined? current_user
105
- end
106
- end
107
- end
108
- end
109
- end
110
- end
@@ -1,38 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require 'active_support/concern'
4
- require_relative 'setup_controller_concern'
5
-
6
- module SnFoil
7
- module Rails
8
- module Controller
9
- module Concerns
10
- module ShowControllerConcern
11
- extend ActiveSupport::Concern
12
-
13
- included do
14
- include SetupControllerConcern
15
- end
16
-
17
- def show(**options)
18
- options = setup_show(**options)
19
- model = process_show(**options)
20
- render_show(model, **options)
21
- end
22
-
23
- def setup_show(**options)
24
- setup_options(**options)
25
- end
26
-
27
- def process_show(**options)
28
- current_context(**options).show(**options)
29
- end
30
-
31
- def render_show(model, **_options)
32
- render model
33
- end
34
- end
35
- end
36
- end
37
- end
38
- end
@@ -1,40 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require 'active_support/concern'
4
- require_relative 'setup_controller_concern'
5
- require_relative 'change_controller_concern'
6
-
7
- module SnFoil
8
- module Rails
9
- module Controller
10
- module Concerns
11
- module UpdateControllerConcern
12
- extend ActiveSupport::Concern
13
-
14
- included do
15
- include SetupControllerConcern
16
- include ChangeControllerConcern
17
- end
18
-
19
- def update(**options)
20
- options = setup_update(**options)
21
- model = process_update(**options)
22
- render_update(model, **options)
23
- end
24
-
25
- def setup_update(**options)
26
- setup_options(**options.merge(deserialize: true))
27
- end
28
-
29
- def process_update(**options)
30
- current_context(**options).update(**options)
31
- end
32
-
33
- def render_update(model, **options)
34
- render_change(model, **options)
35
- end
36
- end
37
- end
38
- end
39
- end
40
- end
@@ -1,10 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require 'rails/railtie'
4
-
5
- module SnFoil
6
- module Rails
7
- class Railtie < ::Rails::Railtie
8
- end
9
- end
10
- end
@@ -1,127 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require 'active_support/concern'
4
- require 'sn_foil/searcher'
5
-
6
- module SnFoil
7
- module Rails
8
- module Searcher
9
- extend ActiveSupport::Concern
10
-
11
- included do
12
- include SnFoil::Searcher
13
-
14
- module_eval do
15
- alias_method :base_search, :search
16
-
17
- # patch the additional search capabilities into the method
18
- def search(params = {})
19
- filtered_scope = base_search(params)
20
- additional_search(filtered_scope, params)
21
- end
22
- end
23
-
24
- ASC ||= 'ASC'
25
- DESC ||= 'DESC'
26
- end
27
-
28
- class_methods do
29
- attr_reader :i_include_params, :i_order_method, :i_order_block, :i_order_by_attr, :i_order_by_direction, :i_is_distinct
30
-
31
- def order(method = nil, &block)
32
- @i_order_method = method
33
- @i_order_block = block
34
- end
35
-
36
- def order_by(attr, direction = nil)
37
- @i_order_by_attr = attr
38
- @i_order_by_direction = direction
39
- end
40
-
41
- def distinct(bool = true)
42
- @i_is_distinct = bool
43
- end
44
-
45
- def includes(*array)
46
- @i_include_params ||= [] # create new array if none exists
47
- @i_include_params |= array # combine unique elements of both arrays
48
- end
49
- end
50
-
51
- def distinct?
52
- self.class.i_is_distinct || false
53
- end
54
-
55
- def included_params
56
- self.class.i_include_params
57
- end
58
-
59
- def order_by(params = {})
60
- if params[:order_by].present?
61
- params[:order_by] = params[:order_by].to_s.underscore
62
- return params[:order_by].to_sym if model.attribute_names.include?(params[:order_by])
63
- end
64
-
65
- self.class.i_order_by_attr || :id
66
- end
67
-
68
- def order(params = {})
69
- if params[:order].present?
70
- params[:order] = params[:order].to_s.upcase
71
- return params[:order] if params[:order].eql?(ASC) || params[:order].eql?(DESC)
72
- end
73
-
74
- self.class.i_order_by_direction || ASC
75
- end
76
-
77
- private
78
-
79
- def additional_search(filtered_scope, params = {})
80
- filtered_scope = apply_order(filtered_scope, params)
81
- filtered_scope = apply_includes(filtered_scope)
82
- apply_distinct(filtered_scope, params)
83
- end
84
-
85
- def apply_includes(filtered_scope)
86
- return filtered_scope unless included_params
87
-
88
- filtered_scope.includes(*included_params)
89
- end
90
-
91
- def apply_order(filtered_scope, params)
92
- return apply_default_order(filtered_scope, params) if params[:order_by].blank? && params[:order].blank?
93
-
94
- filtered_scope.order(order_by(params) => order(params))
95
- end
96
-
97
- def apply_default_order(filtered_scope, params)
98
- return order_method(filtered_scope, params) if order_method?
99
- return order_block(filtered_scope, params) if order_block?
100
-
101
- filtered_scope.order(order_by => order)
102
- end
103
-
104
- def order_method(filtered_scope, params)
105
- send(self.class.i_order_method, filtered_scope, params)
106
- end
107
-
108
- def order_method?
109
- self.class.i_order_method.present?
110
- end
111
-
112
- def order_block(filtered_scope, params)
113
- self.class.i_order_block.call(filtered_scope, params)
114
- end
115
-
116
- def order_block?
117
- self.class.i_order_block.present?
118
- end
119
-
120
- def apply_distinct(filtered_scope, params)
121
- return filtered_scope unless distinct? || params[:distinct] == true
122
-
123
- filtered_scope.distinct
124
- end
125
- end
126
- end
127
- end