restme 1.2.2 → 1.3.1

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 1719cb8e1a96b0e12a5015c3eca4c6acfdb3542d6df849f84abdd2aea05a812b
4
- data.tar.gz: d49bac58ef0983dbbfd4f56710c2b31f8cfe01e1e0d62f886c296b0ea88d98ff
3
+ metadata.gz: 0e523f7df013c44f903677642433e4a602469110597bf654327d1d2ef26bf0b2
4
+ data.tar.gz: 41f22e4c3efe48f3df65165badd1d3a58974f5a8dc183e4c2aeb3fff19b548e8
5
5
  SHA512:
6
- metadata.gz: e703777e66829853afd8fcb560b2d02e3760249ef604d6af9deb9ee6419dcbd5f34f09589d787a9010fd52ac6b78fc744628e77306635bc5b24f9d0a5ec9ec56
7
- data.tar.gz: 474185500814429aed08447b12b89cf9a5109b133354b8ba347d01cb1de7cc81d4a23047e4159761ea6ddb120719e6b4ae3c792222c752c9270f589dd39c7313
6
+ metadata.gz: 3bf751aee7203b756dd96025063c144801db5b2dd568ce9df34dada419985efda09dc8c912b310d09d1fa389dce7c715f66a12e97908776c21fd7174bcae406d
7
+ data.tar.gz: c7a4a9442dbd845ca7e0b07d68992a53e8427a97aa95fd2527c0f36627a5901bfcb7db3ac2cc43a42e722bdf09fc97aec22be3be729951be6c3e4665b6f56330
data/Dockerfile CHANGED
@@ -15,6 +15,8 @@ RUN mkdir -p $APP_HOME
15
15
  WORKDIR $APP_HOME
16
16
 
17
17
  ADD Gemfile* $APP_HOME/
18
+ ADD restme.gemspec $APP_HOME/
19
+ ADD lib/restme/version.rb $APP_HOME/lib/restme/version.rb
18
20
 
19
21
  RUN chown -R $(whoami):$(whoami) $APP_HOME
20
22
 
data/README.md CHANGED
@@ -16,7 +16,7 @@ This gem manages your controller's responsibilities for:
16
16
 
17
17
  GEMFILE:
18
18
  ```bash
19
- gem 'restme', '~> 1.2.1'
19
+ gem 'restme', '~> 1.3.0'
20
20
  ```
21
21
 
22
22
  INSTALL:
@@ -28,7 +28,7 @@ gem 'restme'
28
28
 
29
29
  #### ℹ️ Current Version of gem require the following pré configs
30
30
  - Your controllers must be named using the plural form of the model (e.g., Product → ProductsController). Alternatively, you can manually set the model name by defining the MODEL_NAME constant (e.g., MODEL_NAME = "Product").
31
- - You must create a folder inside app named restfy to define controller rules for authorization, scoping, creation, updating, and field selection (see example below).
31
+ - You must create a folder inside app named restme to define controller rules for authorization, scoping, creation, updating, and field selection (see example below).
32
32
 
33
33
 
34
34
  <br>
@@ -57,6 +57,31 @@ Restme.configure do |config|
57
57
  end
58
58
  ```
59
59
 
60
+ `current_user_variable`
61
+
62
+ Defines the name of the method used to access the currently authenticated user within the controller context.
63
+ This should match the method that returns the logged-in user (for example, :current_user when using authentication libraries like Devise).
64
+ Represent the the field where the role of user is (can be one or many rules)
65
+
66
+ `user_role_field`
67
+
68
+ Defines the attribute on the user model that represents the user's role.
69
+ This field is used to determine authorization rules and may support single or multiple roles, depending on your application's implementation.
70
+
71
+ `pagination_default_per_page`
72
+
73
+ Specifies the default number of records returned per page when pagination parameters are not explicitly provided in the request.
74
+
75
+ `pagination_default_page`
76
+
77
+ Specifies the default page number used when the request does not include a page parameter.
78
+
79
+ `pagination_max_per_page`
80
+
81
+ Defines the maximum number of records allowed per page.
82
+ This acts as a safety limit to prevent clients from requesting excessively large result sets, helping protect application performance and resource usage.
83
+
84
+
60
85
  <br>
61
86
 
62
87
 
@@ -209,6 +234,13 @@ This rule defines which nested_fields are selectable (nested fields are model re
209
234
  ```ruby
210
235
  module ProductsController::Field
211
236
  class Rules
237
+ # Defines the default fields that will be automatically selected
238
+ # in queries when no explicit field selection is provided.
239
+ # These fields are always included in the response.
240
+ MODEL_FIELDS_SELECT = %i[id].freeze
241
+
242
+ UNALLOWED_MODEL_FIELDS_SELECT = %i[internal_code].freeze
243
+
212
244
  NESTED_SELECTABLE_FIELDS = {
213
245
  unit: {},
214
246
  establishment: {},
@@ -288,8 +320,6 @@ There are two query parameters available to control pagination:
288
320
  - `per_page`: Defines the number of items per page.
289
321
  - `page`: Sets the current page number.
290
322
 
291
- ℹ️ **Note:** The maximum number of items per page is currently limited to 100.
292
-
293
323
  Example usage:
294
324
 
295
325
  ```bash
@@ -301,8 +331,8 @@ http://localhost:3000/api/v1/products?per_page=12&page=1
301
331
 
302
332
  #### Field Selection (`fields_select`)
303
333
 
304
- You can select specific fields from your model, such as `id`, `name`, or `created_at`.
305
- The resulting query will retrieve **only** the selected fields directly from the database, improving performance.
334
+ You can select specific fields from your model, such as `id`, `name`, or `created_at`.
335
+ The generated query will retrieve only the selected fields directly from the database, reducing unnecessary data loading and improving performance.
306
336
 
307
337
  Example:
308
338
 
@@ -1,6 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require_relative "../shared/restme_current_user_role"
3
+ require_relative "../shared/restme_current_user_roles"
4
4
  require_relative "../shared/current_model"
5
5
 
6
6
  module Restme
@@ -8,7 +8,7 @@ module Restme
8
8
  # Defines the rules used to authotize user
9
9
  module Rules
10
10
  include ::Restme::Shared::CurrentModel
11
- include ::Restme::Shared::RestmeCurrentUserRole
11
+ include ::Restme::Shared::RestmeCurrentUserRoles
12
12
 
13
13
  def user_authorized?
14
14
  return true if restme_current_user.blank? || authorize?
@@ -19,8 +19,7 @@ module Restme
19
19
  end
20
20
 
21
21
  def authorize?
22
- allowed_roles_actions[action_name.to_sym]
23
- &.include?(restme_current_user_role&.to_sym)
22
+ (allowed_roles_actions & restme_current_user_roles)&.any?
24
23
  end
25
24
 
26
25
  def authorize_errors
@@ -35,9 +34,9 @@ module Restme
35
34
  end
36
35
 
37
36
  def allowed_roles_actions
38
- return {} unless authorize_rules_class&.const_defined?(:ALLOWED_ROLES_ACTIONS)
37
+ return [] unless authorize_rules_class&.const_defined?(:ALLOWED_ROLES_ACTIONS)
39
38
 
40
- authorize_rules_class::ALLOWED_ROLES_ACTIONS
39
+ authorize_rules_class::ALLOWED_ROLES_ACTIONS[action_name.to_sym] || []
41
40
  end
42
41
 
43
42
  def authorize_rules_class
@@ -1,6 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require_relative "../shared/restme_current_user_role"
3
+ require_relative "../shared/restme_current_user_roles"
4
4
  require_relative "../shared/current_model"
5
5
  require_relative "../shared/controller_params"
6
6
 
@@ -10,7 +10,7 @@ module Restme
10
10
  module Rules
11
11
  include ::Restme::Shared::ControllerParams
12
12
  include ::Restme::Shared::CurrentModel
13
- include ::Restme::Shared::RestmeCurrentUserRole
13
+ include ::Restme::Shared::RestmeCurrentUserRoles
14
14
 
15
15
  attr_reader :create_temp_record
16
16
 
@@ -34,7 +34,7 @@ module Restme
34
34
  end
35
35
 
36
36
  def restme_create_status
37
- return :unprocessable_entity if create_record_errors
37
+ return :unprocessable_content if create_record_errors
38
38
 
39
39
  :created
40
40
  end
@@ -64,9 +64,13 @@ module Restme
64
64
  def createable_scope?
65
65
  return true unless restme_current_user
66
66
 
67
- method_scope = "#{creatable_current_action}_#{restme_current_user_role}_scope?"
67
+ restme_create_methods_scopes.any? { |method_scope| create_rules_class.try(method_scope) }
68
+ end
68
69
 
69
- create_rules_class.try(method_scope) || false
70
+ def restme_create_methods_scopes
71
+ @restme_create_methods_scopes ||= restme_current_user_roles.map do |restme_role|
72
+ "#{creatable_current_action}_#{restme_role}_scope?"
73
+ end
70
74
  end
71
75
 
72
76
  def createable_object_errors_messages
@@ -78,7 +82,7 @@ module Restme
78
82
  end
79
83
 
80
84
  def creatable_current_action
81
- return true unless restme_current_user
85
+ return unless create_rules_class
82
86
 
83
87
  current_action.presence_in create_rules_class.class::CREATABLE_ACTIONS_RULES
84
88
  rescue StandardError
@@ -25,10 +25,13 @@ module Restme
25
25
 
26
26
  def define_attachment_methods
27
27
  attachment_fields_select.each do |attachment_field_name|
28
- klass.class_eval do
29
- define_method(:"#{attachment_field_name}_url") do
30
- send(attachment_field_name).url
31
- end
28
+ method_name = "#{attachment_field_name}_url"
29
+
30
+ next if klass.method_defined?(method_name)
31
+
32
+ klass.define_method(method_name) do
33
+ attachment = public_send(attachment_field_name)
34
+ attachment&.url
32
35
  end
33
36
  end
34
37
  end
@@ -50,10 +53,9 @@ module Restme
50
53
  def unallowed_attachment_fields_error
51
54
  return if unallowed_attachment_fields.blank?
52
55
 
53
- render json: {
54
- body: unallowed_attachment_fields,
55
- message: "Selected not allowed attachment fields"
56
- }, status: :bad_request
56
+ restme_scope_errors({ body: unallowed_attachment_fields, message: "Selected not allowed attachment fields" })
57
+
58
+ restme_scope_status(:bad_request)
57
59
  end
58
60
 
59
61
  def unallowed_attachment_fields
@@ -30,19 +30,31 @@ module Restme
30
30
  end
31
31
 
32
32
  def select_any_field?
33
- fields_select || nested_fields_select || attachment_fields_select
33
+ defined_fields_select || fields_select || nested_fields_select || attachment_fields_select
34
34
  end
35
35
 
36
36
  def model_fields_select
37
- @model_fields_select ||= begin
38
- fields = fields_select&.split(",")
39
- fields = fields&.map { |field| "#{klass.table_name}.#{field}" }&.join(",")
40
- fields || model_attributes
41
- end
37
+ @model_fields_select ||= select_selected_fields.presence || model_attributes
38
+ end
39
+
40
+ def select_selected_fields
41
+ @select_selected_fields ||= defined_fields_select | fields_select.split(",").map(&:to_s)
42
42
  end
43
43
 
44
44
  def model_attributes
45
- @model_attributes ||= klass.new.attributes.keys
45
+ @model_attributes ||= klass.attribute_names - unallowed_model_fields_select
46
+ end
47
+
48
+ def defined_fields_select
49
+ return [] unless field_class_rules&.const_defined?(:MODEL_FIELDS_SELECT)
50
+
51
+ (field_class_rules::MODEL_FIELDS_SELECT || []).map(&:to_s)
52
+ end
53
+
54
+ def unallowed_model_fields_select
55
+ return [] unless field_class_rules&.const_defined?(:UNALLOWED_MODEL_FIELDS_SELECT)
56
+
57
+ (field_class_rules::UNALLOWED_MODEL_FIELDS_SELECT || []).map(&:to_s)
46
58
  end
47
59
 
48
60
  def valid_nested_fields_select
@@ -79,7 +91,7 @@ module Restme
79
91
  end
80
92
 
81
93
  def fields_select
82
- @fields_select ||= controller_query_params[:fields_select]
94
+ @fields_select ||= controller_query_params[:fields_select] || ""
83
95
  end
84
96
 
85
97
  def nested_fields_select
@@ -1,6 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require_relative "../shared/restme_current_user_role"
3
+ require_relative "../shared/restme_current_user_roles"
4
4
  require_relative "../shared/current_model"
5
5
  require_relative "../shared/controller_params"
6
6
  require_relative "filter/rules"
@@ -20,7 +20,7 @@ module Restme
20
20
  include ::Restme::Scope::Filter::Rules
21
21
  include ::Restme::Shared::ControllerParams
22
22
  include ::Restme::Shared::CurrentModel
23
- include ::Restme::Shared::RestmeCurrentUserRole
23
+ include ::Restme::Shared::RestmeCurrentUserRoles
24
24
 
25
25
  attr_reader :filterable_scope_response
26
26
  attr_writer :restme_scope_errors, :restme_scope_status
@@ -30,6 +30,7 @@ module Restme
30
30
  unknown_sortable_fields_errors
31
31
  unallowed_filter_fields_errors
32
32
  unallowed_select_fields_errors
33
+ unallowed_attachment_fields_error
33
34
  ].freeze
34
35
 
35
36
  def pagination_response
@@ -99,7 +100,22 @@ module Restme
99
100
  end
100
101
 
101
102
  def user_scope
102
- @user_scope ||= none_user_scope || scope_rules_class.try(method_scope) || none_scope
103
+ @user_scope ||= none_user_scope || process_user_scope || none_scope
104
+ end
105
+
106
+ def process_user_scope
107
+ scopes = user_scope_methods.map { |m| scope_rules_class.try(m) }
108
+
109
+ processed_scope = scopes.reduce { |combined, s| combined.or(s) }
110
+
111
+ user_scope_methods.many? ? processed_scope&.distinct : processed_scope
112
+ end
113
+
114
+ def user_scope_methods
115
+ @user_scope_methods ||=
116
+ restme_methods_scopes.select do |method_scope|
117
+ scope_rules_class.respond_to?(method_scope)
118
+ end
103
119
  end
104
120
 
105
121
  def none_user_scope
@@ -110,8 +126,10 @@ module Restme
110
126
  klass.none
111
127
  end
112
128
 
113
- def method_scope
114
- "#{restme_current_user_role}_scope"
129
+ def restme_methods_scopes
130
+ @restme_methods_scopes ||= restme_current_user_roles.map do |restme_role|
131
+ "#{restme_role}_scope"
132
+ end
115
133
  end
116
134
 
117
135
  def scope_rules_class
@@ -0,0 +1,18 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Restme
4
+ module Shared
5
+ # Returns the roles associated with the user, always normalized as an Array of symbols.
6
+ module RestmeCurrentUserRoles
7
+ def restme_current_user_roles
8
+ Array.wrap(user_roles).map do |role|
9
+ role.respond_to?(:to_sym) ? role.to_sym : role.to_s.to_sym
10
+ end
11
+ end
12
+
13
+ def user_roles
14
+ @user_roles ||= restme_current_user&.try(::Restme::Configuration.user_role_field)
15
+ end
16
+ end
17
+ end
18
+ end
@@ -1,6 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require_relative "../shared/restme_current_user_role"
3
+ require_relative "../shared/restme_current_user_roles"
4
4
  require_relative "../shared/current_model"
5
5
  require_relative "../shared/controller_params"
6
6
 
@@ -10,7 +10,7 @@ module Restme
10
10
  module Rules
11
11
  include ::Restme::Shared::ControllerParams
12
12
  include ::Restme::Shared::CurrentModel
13
- include ::Restme::Shared::RestmeCurrentUserRole
13
+ include ::Restme::Shared::RestmeCurrentUserRoles
14
14
 
15
15
  attr_reader :update_temp_record
16
16
 
@@ -36,7 +36,7 @@ module Restme
36
36
  end
37
37
 
38
38
  def restme_update_status
39
- return :unprocessable_entity if update_record_errors
39
+ return :unprocessable_content if update_record_errors
40
40
 
41
41
  :ok
42
42
  end
@@ -74,9 +74,13 @@ module Restme
74
74
  def updateable_scope?
75
75
  return true unless restme_current_user
76
76
 
77
- method_scope = "#{updateable_current_action}_#{restme_current_user_role}_scope?"
77
+ restme_update_methods_scopes.any? { |method_scope| update_rules_class.try(method_scope) }
78
+ end
78
79
 
79
- update_rules_class.try(method_scope) || false
80
+ def restme_update_methods_scopes
81
+ @restme_update_methods_scopes ||= restme_current_user_roles.map do |restme_role|
82
+ "#{updateable_current_action}_#{restme_role}_scope?"
83
+ end
80
84
  end
81
85
 
82
86
  def updateable_record_errors_messages
@@ -88,7 +92,7 @@ module Restme
88
92
  end
89
93
 
90
94
  def updateable_current_action
91
- return true unless restme_current_user
95
+ return unless update_rules_class
92
96
 
93
97
  current_action.presence_in update_rules_class.class::UPDATABLE_ACTIONS_RULES
94
98
  rescue StandardError
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Restme
4
- VERSION = "1.2.2"
4
+ VERSION = "1.3.1"
5
5
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: restme
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.2.2
4
+ version: 1.3.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - everson-ever
@@ -46,7 +46,7 @@ files:
46
46
  - lib/restme/scope/sort/rules.rb
47
47
  - lib/restme/shared/controller_params.rb
48
48
  - lib/restme/shared/current_model.rb
49
- - lib/restme/shared/restme_current_user_role.rb
49
+ - lib/restme/shared/restme_current_user_roles.rb
50
50
  - lib/restme/update/rules.rb
51
51
  - lib/restme/version.rb
52
52
  - sig/restme.rbs
@@ -1,12 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module Restme
4
- module Shared
5
- # Returns the roles associated with the user, if any exist.
6
- module RestmeCurrentUserRole
7
- def restme_current_user_role
8
- restme_current_user&.try(::Restme::Configuration.user_role_field)
9
- end
10
- end
11
- end
12
- end