active_manageable 0.1.2 → 0.3.0

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.
Files changed (36) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/ci.yml +23 -11
  3. data/.gitignore +1 -1
  4. data/.rubocop.yml +12 -19
  5. data/Appraisals +19 -10
  6. data/CHANGELOG.md +18 -0
  7. data/Gemfile.lock +179 -108
  8. data/README.md +81 -11
  9. data/active_manageable.gemspec +7 -7
  10. data/gemfiles/rails_7_0.gemfile +9 -2
  11. data/gemfiles/{rails_6_1.gemfile → rails_7_1.gemfile} +2 -2
  12. data/gemfiles/{rails_6_0.gemfile → rails_7_2.gemfile} +2 -2
  13. data/lib/active_manageable/authorization/cancancan.rb +10 -12
  14. data/lib/active_manageable/authorization/pundit.rb +10 -12
  15. data/lib/active_manageable/base.rb +16 -5
  16. data/lib/active_manageable/configuration.rb +16 -7
  17. data/lib/active_manageable/methods/auxiliary/includes.rb +28 -30
  18. data/lib/active_manageable/methods/auxiliary/model_attributes.rb +15 -17
  19. data/lib/active_manageable/methods/auxiliary/order.rb +12 -14
  20. data/lib/active_manageable/methods/auxiliary/scopes.rb +35 -28
  21. data/lib/active_manageable/methods/auxiliary/select.rb +11 -13
  22. data/lib/active_manageable/methods/auxiliary/unique_search.rb +19 -19
  23. data/lib/active_manageable/methods/create.rb +20 -5
  24. data/lib/active_manageable/methods/destroy.rb +22 -7
  25. data/lib/active_manageable/methods/edit.rb +17 -9
  26. data/lib/active_manageable/methods/index.rb +28 -26
  27. data/lib/active_manageable/methods/new.rb +14 -6
  28. data/lib/active_manageable/methods/show.rb +17 -9
  29. data/lib/active_manageable/methods/update.rb +28 -7
  30. data/lib/active_manageable/pagination/kaminari.rb +29 -9
  31. data/lib/active_manageable/search/ransack.rb +15 -17
  32. data/lib/active_manageable/version.rb +1 -1
  33. metadata +36 -28
  34. data/.rubocop_rails.yml +0 -201
  35. data/.rubocop_rspec.yml +0 -68
  36. data/.standard.yml +0 -5
data/README.md CHANGED
@@ -49,7 +49,7 @@ def index
49
49
  end
50
50
  ```
51
51
 
52
- The manager classes provide standard implementations of the seven core CRUD methods. These can be overwritten to perform custom business logic and the classes can also be extended to include the business logic for additional actions, both making use of the internal ActiveManageable methods and variables described in the [Adding Bespoke Methods](#adding-bespoke-methods) section.
52
+ The manager classes provide standard implementations of the seven core CRUD methods. These can be extended or overwritten to perform custom business logic and the classes can also be extended to include the business logic for additional actions, both making use of the internal ActiveManageable methods and variables described in the [Adding Bespoke Methods](#adding-bespoke-methods) section.
53
53
 
54
54
  With an Activity model in a CRM application to manage meetings & tasks, a complete action may be required. This could be implemented as follows:
55
55
 
@@ -110,6 +110,7 @@ gem install active_manageable
110
110
  - [Default Scopes](#default-scopes)
111
111
  - [Unique Search](#unique-search)
112
112
  - [Default Page Size](#default-page-size)
113
+ - [Paginate Without Count](#paginate-without-count)
113
114
  - [Current Method](#current-method)
114
115
  - [Index Method](#index-method)
115
116
  - [Authorization Scope](#index-authorization-scope)
@@ -131,6 +132,8 @@ gem install active_manageable
131
132
  - [Includes Option](#update-includes-option)
132
133
  - [Destroy Method](#destroy-method)
133
134
  - [Includes Option](#destroy-includes-option)
135
+ - [Extending the CRUD Methods](#extending-the-crud-methods)
136
+ - [Build and Retrieve Scoped Records](#build-and-retrieve-scoped-records)
134
137
  - [Attribute Value Parsing](#attribute-value-parsing)
135
138
  - [Date and DateTime Attribute Values](#date-and-datetime-attribute-values)
136
139
  - [Numeric Attribute Values](#numeric-attribute-values)
@@ -143,7 +146,7 @@ gem install active_manageable
143
146
 
144
147
  ## Configuration
145
148
 
146
- Create an initializer to configure the optional authorization, search and pagination libraries to use.
149
+ Create an initializer to configure the optional in-built authorization, search and pagination libraries to use.
147
150
 
148
151
  ```ruby
149
152
  ActiveManageable.config do |config|
@@ -153,6 +156,8 @@ ActiveManageable.config do |config|
153
156
  end
154
157
  ```
155
158
 
159
+ These library configuration options can also be set to a module in order to use a custom authorization, search or pagination implementation.
160
+
156
161
  When eager loading associations the `includes` method is used by default but this can be changed via a configuration option that accepts `:includes`, `:preload` or `:eager_load`
157
162
 
158
163
  ```ruby
@@ -388,6 +393,31 @@ class AlbumManager < ActiveManageable::Base
388
393
  end
389
394
  ```
390
395
 
396
+ ### Paginate Without Count
397
+
398
+ When using the [Kaminari](https://github.com/kaminari/kaminari) pagination library, the `paginate_without_count` method will result in the index method using the Kaminari `without_count` mode to create a paginatable collection without counting the total number of records.
399
+
400
+ ```ruby
401
+ class AlbumManager < ActiveManageable::Base
402
+ manageable :index
403
+ paginate_without_count
404
+ end
405
+ ```
406
+
407
+ It is also possible to control whether to use the `without_count` mode globally by setting the `paginate_without_count` configuration option.
408
+
409
+ ```ruby
410
+ ActiveManageable.config do |config|
411
+ config.paginate_without_count = true
412
+ end
413
+ ```
414
+
415
+ And it is also possible to control whether to use the `without_count` mode for an individual index method call by including the `:without_count` key within the `options` argument `:page` hash.
416
+
417
+ ```ruby
418
+ manager.index(options: {page: {number: 2, size: 10, without_count: true}})
419
+ ```
420
+
391
421
  ### Current Method
392
422
 
393
423
  ActiveManageable includes a `current_method` attribute which returns the name of the method being executed as a symbol, which can potentially be used within methods in conjunction with a lambda for the default methods described above. Additionally, the method argument `options` and `attributes` are also accessible as attributes.
@@ -411,7 +441,7 @@ end
411
441
 
412
442
  ## Index Method
413
443
 
414
- The `index` method has an optional `options` keyword argument. The `options` hash can contain `:search`, `:order`, `:scopes`, `:page`, `:includes` and `:select` keys. The method performs authorization for the current user, method and model class using the configuration library; retrieves record using the various options described below; and returns the records which are also accessible via the `collection` attribute.
444
+ The `index` method has an optional `options` keyword argument. The `options` hash can contain `:search`, `:order`, `:scopes`, `:page`, `:includes` and `:select` keys. The method performs authorization for the current user, method and model class using the configuration library; invokes a block (if provided); retrieves records using the various options described below; and returns the records which are also accessible via the `collection` attribute.
415
445
 
416
446
  ```ruby
417
447
  manager.index
@@ -490,7 +520,7 @@ If the class `has_unique_search` method has been used then this will be evaluate
490
520
 
491
521
  ## Show Method
492
522
 
493
- The `show` method has `id` and optional `options` keyword arguments. The `options` hash can contain `:includes` and `:select` keys. The method retrieves a record; performs authorization for the current user, method and record using the configuration library; and returns the record which is also accessible via the `object` attribute.
523
+ The `show` method has `id` and optional `options` keyword arguments. The `options` hash can contain `:includes` and `:select` keys. The method invokes a block (if provided); retrieves a record; performs authorization for the current user, method and record using the configuration library; and returns the record which is also accessible via the `object` attribute.
494
524
 
495
525
  ```ruby
496
526
  manager.show(id: 1)
@@ -520,7 +550,7 @@ manager.show(id: 1, options: {select: [:id, :name, :artist_id, :released_at]})
520
550
 
521
551
  ## New Method
522
552
 
523
- The `new` method has an optional `attributes` keyword argument. The `attributes` argument is for an `ActionController::Parameters` or hash of attribute names and values to use when building the record. The method builds a record; performs authorization for the current user, method and record using the configuration library; and returns the record which is also accessible via the `object` attribute.
553
+ The `new` method has an optional `attributes` keyword argument. The `attributes` argument is for an `ActionController::Parameters` or hash of attribute names and values to use when building the record. The method builds a record; performs authorization for the current user, method and record using the configuration library; invokes a block (if provided); and returns the record which is also accessible via the `object` attribute.
524
554
 
525
555
  ```ruby
526
556
  manager.new
@@ -534,7 +564,7 @@ manager.new(attributes: {genre: "electronic", published_at: Date.current})
534
564
 
535
565
  ## Create Method
536
566
 
537
- The `create` method has an `attributes` keyword argument. The `attributes` argument is for an `ActionController::Parameters` or hash of attribute names and values to use when building the record. The method builds a record; performs authorization for the current user, method and record using the configuration library; attempts to save the record and returns the save result. The record is also accessible via the `object` attribute.
567
+ The `create` method has an `attributes` keyword argument. The `attributes` argument is for an `ActionController::Parameters` or hash of attribute names and values to use when building the record. The method builds a record; performs authorization for the current user, method and record using the configuration library; invokes a block (if provided) and attempts to save the record within a transaction; and returns the save result. The record is also accessible via the `object` attribute.
538
568
 
539
569
  ```ruby
540
570
  manager.create(attributes: {name: "Substance", genre: "electronic", published_at: Date.current})
@@ -544,7 +574,7 @@ The `attributes` argument values are combined with the class default values and
544
574
 
545
575
  ## Edit Method
546
576
 
547
- The `edit` method has `id` and optional `options` keyword arguments. The `options` hash can contain `:includes` and `:select` keys. The method retrieves a record; performs authorization for the current user, method and record using the configuration library; and returns the record which is also accessible via the `object` attribute.
577
+ The `edit` method has `id` and optional `options` keyword arguments. The `options` hash can contain `:includes` and `:select` keys. The method invokes a block (if provided); retrieves a record; performs authorization for the current user, method and record using the configuration library; and returns the record which is also accessible via the `object` attribute.
548
578
 
549
579
  ```ruby
550
580
  manager.edit(id: 1)
@@ -566,7 +596,7 @@ manager.edit(id: 1, options: {includes: {associations: :songs, loading_method: :
566
596
 
567
597
  ## Update Method
568
598
 
569
- The `update` method has `id`, `attributes` and optional `options` keyword arguments. The `attributes` argument is for an `ActionController::Parameters` or hash of attribute names and values to use when updating the record. The `options` hash can contain an `:includes` key. The method retrieves a record; performs authorization for the current user, method and record using the configuration library; updates the attributes; attempts to save the record and returns the save result. The record is also accessible via the `object` attribute.
599
+ The `update` method has `id`, `attributes` and optional `options` keyword arguments. The `attributes` argument is for an `ActionController::Parameters` or hash of attribute names and values to use when updating the record. The `options` hash can contain an `:includes` key. The method retrieves a record; performs authorization for the current user, method and record using the configuration library; assigns the attributes; invokes a block (if provided) and attempts to save the record within a transaction; and returns the save result. The record is also accessible via the `object` attribute.
570
600
 
571
601
  ```ruby
572
602
  manager.update(id: 1, attributes: {genre: "electronic", published_at: Date.current})
@@ -588,7 +618,7 @@ manager.update(id: 1, attributes: {published_at: Date.current}, options: {includ
588
618
 
589
619
  ## Destroy Method
590
620
 
591
- The `destroy` method has `id` and optional `options` keyword arguments. The `options` hash can contain an `:includes` key. The method retrieves a record; performs authorization for the current user, method and record using the configuration library; attempts to destroy the record and returns the destroy result. The record is accessible via the `object` attribute.
621
+ The `destroy` method has `id` and optional `options` keyword arguments. The `options` hash can contain an `:includes` key. The method retrieves a record; performs authorization for the current user, method and record using the configuration library; invokes a block (if provided) and attempts to destroy the record within a transaction; and returns the destroy result. The record is accessible via the `object` attribute.
592
622
 
593
623
  ```ruby
594
624
  manager.destroy(id: 1)
@@ -608,6 +638,37 @@ The `:includes` key can also be used to vary the method used to eager load assoc
608
638
  manager.destroy(id: 1, options: {includes: {associations: :songs, loading_method: :preload}})
609
639
  ```
610
640
 
641
+ ## Extending the CRUD Methods
642
+
643
+ Each of the seven core CRUD methods include a `yield` so it is possible to extend the methods by passing a block.
644
+
645
+ ```ruby
646
+ def create(attributes:)
647
+ super do
648
+ @target.description = "change the object before it is created using a block"
649
+ end
650
+ end
651
+ ```
652
+
653
+ The logic within each of the methods has also been split into subsidiary methods so it is possible to extend or override these methods.
654
+
655
+ ```ruby
656
+ def create_object
657
+ @target.description = "change the object before it is created via an override"
658
+ super
659
+ end
660
+ ```
661
+
662
+ ## Build and Retrieve Scoped Records
663
+
664
+ Each of the seven core CRUD methods build and retrieve records using the `action_scope` method which by default returns the model class. In order to build or retrieve records using a scope it is possible to override this method.
665
+
666
+ ```ruby
667
+ def action_scope
668
+ current_user.albums
669
+ end
670
+ ```
671
+
611
672
  ## Attribute Value Parsing
612
673
 
613
674
  ### Date and DateTime Attribute Values
@@ -693,7 +754,7 @@ ActiveManageable includes the following attributes:
693
754
 
694
755
  ## Adding Bespoke Methods
695
756
 
696
- The manager classes provide standard implementations of the seven core CRUD methods. These can be overwritten to perform custom business logic and the classes can also be extended to include the business logic for additional actions, both making use of the internal ActiveManageable methods and variables.
757
+ The manager classes provide standard implementations of the seven core CRUD methods. These can be extended or overwritten to perform custom business logic and the classes can also be extended to include the business logic for additional actions, both making use of the internal ActiveManageable methods and variables.
697
758
 
698
759
  ```ruby
699
760
  def complete(id:)
@@ -737,7 +798,16 @@ After making changes:
737
798
  4. run `bundle exec appraisal rspec` to run the tests against different versions of activerecord & activesupport
738
799
  5. run `bundle exec rubocop` to check the style of files
739
800
 
740
- To install this gem onto your local machine, run `bundle exec rake install`. To release a new version, update the version number in `version.rb`, and then run `bundle exec rake release`, which will create a git tag for the version, push git commits and the created tag, and push the `.gem` file to [rubygems.org](https://rubygems.org).
801
+ To install this gem onto your local machine, run `bundle exec rake install`.
802
+
803
+ To release a new version:
804
+
805
+ 1. update the version number in `version.rb`
806
+ 2. update the change log in `CHANGELOG.md`
807
+ 3. run `bundle` to update the `Gemfile.lock` version
808
+ 4. commit the changes
809
+ 5. run `bundle exec rake release` to create & push a git tag for the version and push the `.gem` file to [rubygems.org](https://rubygems.org).
810
+ 6. create a new release for the version on GitHub
741
811
 
742
812
  ## Contributing
743
813
 
@@ -14,8 +14,7 @@ Gem::Specification.new do |spec|
14
14
  spec.homepage = "https://github.com/CircleSD/active_manageable"
15
15
  spec.license = "MIT"
16
16
 
17
- # Minimum version of Ruby compatible with Rails 7.0
18
- spec.required_ruby_version = ">= 2.7.0"
17
+ spec.required_ruby_version = ">= 3.0.0"
19
18
 
20
19
  # Metadata used on gem’s profile page on rubygems.org
21
20
  spec.metadata["homepage_uri"] = spec.homepage
@@ -41,17 +40,17 @@ Gem::Specification.new do |spec|
41
40
  # including gems that are essential to test and build this gem
42
41
 
43
42
  # rails dependencies
44
- spec.add_dependency "activerecord", ">= 6.0"
45
- spec.add_dependency "activesupport", ">= 6.0"
43
+ spec.add_dependency "activerecord", ">= 7.0"
44
+ spec.add_dependency "activesupport", ">= 7.0"
46
45
 
47
46
  # gem dependencies
48
47
  spec.add_dependency "rails-i18n"
49
48
  spec.add_dependency "flexitime", "~> 1.0"
50
49
 
51
50
  # test dependencies
52
- spec.add_development_dependency "rake", "~> 13.0"
51
+ spec.add_development_dependency "rake"
53
52
  spec.add_development_dependency "appraisal"
54
- spec.add_development_dependency "sqlite3", "~> 1.4.0"
53
+ spec.add_development_dependency "sqlite3"
55
54
  spec.add_development_dependency "rspec-rails"
56
55
  spec.add_development_dependency "rails-controller-testing"
57
56
  spec.add_development_dependency "factory_bot_rails"
@@ -65,8 +64,9 @@ Gem::Specification.new do |spec|
65
64
  spec.add_development_dependency "kaminari"
66
65
 
67
66
  # linter dependencies
68
- spec.add_development_dependency "rubocop", "1.23.0"
67
+ spec.add_development_dependency "rubocop"
69
68
  spec.add_development_dependency "standard"
69
+ spec.add_development_dependency "standard-rails"
70
70
  spec.add_development_dependency "rubocop-rails"
71
71
  spec.add_development_dependency "rubocop-rspec"
72
72
 
@@ -2,7 +2,14 @@
2
2
 
3
3
  source "https://rubygems.org"
4
4
 
5
- gem "activerecord", "~> 7.0"
6
- gem "activesupport", "~> 7.0"
5
+ gem "activerecord", "~> 7.0.0"
6
+ gem "activesupport", "~> 7.0.0"
7
+ gem "sqlite3", "~> 1.4"
8
+ gem "logger"
9
+ gem "base64"
10
+ gem "bigdecimal"
11
+ gem "mutex_m"
12
+ gem "drb"
13
+ gem "benchmark"
7
14
 
8
15
  gemspec path: "../"
@@ -2,7 +2,7 @@
2
2
 
3
3
  source "https://rubygems.org"
4
4
 
5
- gem "activerecord", "~> 6.1"
6
- gem "activesupport", "~> 6.1"
5
+ gem "activerecord", "~> 7.1.0"
6
+ gem "activesupport", "~> 7.1.0"
7
7
 
8
8
  gemspec path: "../"
@@ -2,7 +2,7 @@
2
2
 
3
3
  source "https://rubygems.org"
4
4
 
5
- gem "activerecord", "~> 6.0.1"
6
- gem "activesupport", "~> 6.0.1"
5
+ gem "activerecord", "~> 7.2.0"
6
+ gem "activesupport", "~> 7.2.0"
7
7
 
8
8
  gemspec path: "../"
@@ -7,21 +7,19 @@ module ActiveManageable
7
7
  module CanCanCan
8
8
  extend ActiveSupport::Concern
9
9
 
10
- included do
11
- private
10
+ private
12
11
 
13
- def authorize(record:, action: nil)
14
- action ||= @current_method
15
- current_ability.authorize!(action, record)
16
- end
12
+ def authorize(record:, action: nil)
13
+ action ||= @current_method
14
+ current_ability.authorize!(action, record)
15
+ end
17
16
 
18
- def scoped_class
19
- model_class.accessible_by(current_ability)
20
- end
17
+ def authorization_scope
18
+ model_class.accessible_by(current_ability)
19
+ end
21
20
 
22
- def current_ability
23
- ::Ability.new(current_user)
24
- end
21
+ def current_ability
22
+ ::Ability.new(current_user)
25
23
  end
26
24
  end
27
25
  end
@@ -7,21 +7,19 @@ module ActiveManageable
7
7
  module Pundit
8
8
  extend ActiveSupport::Concern
9
9
 
10
- included do
11
- private
10
+ private
12
11
 
13
- def authorize(record:, action: nil)
14
- action ||= authorize_action
15
- ::Pundit.authorize(current_user, record, action)
16
- end
12
+ def authorize(record:, action: nil)
13
+ action ||= authorize_action
14
+ ::Pundit.authorize(current_user, record, action)
15
+ end
17
16
 
18
- def scoped_class
19
- ::Pundit.policy_scope(current_user, model_class)
20
- end
17
+ def authorization_scope
18
+ ::Pundit.policy_scope(current_user, model_class)
19
+ end
21
20
 
22
- def authorize_action
23
- "#{@current_method}?".to_sym
24
- end
21
+ def authorize_action
22
+ :"#{@current_method}?"
25
23
  end
26
24
  end
27
25
  end
@@ -4,12 +4,13 @@ module ActiveManageable
4
4
  class_attribute :defaults, instance_writer: false, instance_predicate: false
5
5
  class_attribute :module_initialize_state_methods, instance_writer: false, instance_predicate: false
6
6
 
7
- attr_reader :target, :current_method, :attributes, :options
7
+ attr_accessor :target
8
+ attr_reader :current_method, :attributes, :options
8
9
 
9
10
  # target provides a common variable to use within the CRUD, auxiliary & library methods
10
11
  # whereas the object & collection methods provide less ambiguous external access
11
- alias_method :object, :target
12
- alias_method :collection, :target
12
+ alias_attribute :object, :target
13
+ alias_attribute :collection, :target
13
14
 
14
15
  class << self
15
16
  # Ruby method called when a child class inherits from a parent class
@@ -58,6 +59,8 @@ module ActiveManageable
58
59
  include ActiveManageable::Authorization::Pundit
59
60
  when :cancancan
60
61
  include ActiveManageable::Authorization::CanCanCan
62
+ when Module
63
+ include ActiveManageable.configuration.authorization_library
61
64
  end
62
65
  end
63
66
 
@@ -65,6 +68,8 @@ module ActiveManageable
65
68
  case ActiveManageable.configuration.search_library
66
69
  when :ransack
67
70
  include ActiveManageable::Search::Ransack
71
+ when Module
72
+ include ActiveManageable.configuration.search_library
68
73
  end
69
74
  end
70
75
 
@@ -72,6 +77,8 @@ module ActiveManageable
72
77
  case ActiveManageable.configuration.pagination_library
73
78
  when :kaminari
74
79
  include ActiveManageable::Pagination::Kaminari
80
+ when Module
81
+ include ActiveManageable.configuration.pagination_library
75
82
  end
76
83
  end
77
84
 
@@ -109,6 +116,10 @@ module ActiveManageable
109
116
 
110
117
  private
111
118
 
119
+ def action_scope
120
+ model_class
121
+ end
122
+
112
123
  def initialize_state(attributes: {}, options: {})
113
124
  @target = nil
114
125
  @current_method = calling_method
@@ -126,8 +137,8 @@ module ActiveManageable
126
137
  # when the ransack module is included as it has its own definition of the method that calls super
127
138
  # https://www.lucascaton.com.br/2016/11/04/ruby-how-to-get-the-name-of-the-calling-method
128
139
  def calling_method
129
- my_caller = caller_locations(1..1).first.label
130
- caller_locations[1..].find { |location| location.label != my_caller }.label.to_sym
140
+ my_caller = caller_locations(1..1).first.base_label
141
+ caller_locations[1..].find { |location| location.base_label != my_caller }.base_label.to_sym
131
142
  end
132
143
 
133
144
  # Converts a state argument to a ActiveSupport::HashWithIndifferentAccess.
@@ -6,31 +6,32 @@ module ActiveManageable
6
6
 
7
7
  class Configuration
8
8
  attr_reader :authorization_library, :search_library, :pagination_library, :default_loading_method
9
- attr_accessor :subclass_suffix
9
+ attr_accessor :subclass_suffix, :paginate_without_count
10
10
 
11
11
  def initialize
12
12
  @default_loading_method = :includes
13
13
  @subclass_suffix = "Manager"
14
+ @paginate_without_count = false
14
15
  end
15
16
 
16
17
  def authorization_library=(authorization_library)
17
18
  raise ArgumentError.new("Invalid authorization library") unless authorization_library_valid?(authorization_library)
18
- @authorization_library = authorization_library.to_sym
19
+ @authorization_library = authorization_library
19
20
  end
20
21
 
21
22
  def search_library=(search_library)
22
23
  raise ArgumentError.new("Invalid search library") unless search_library_valid?(search_library)
23
- @search_library = search_library.to_sym
24
+ @search_library = search_library
24
25
  end
25
26
 
26
27
  def pagination_library=(pagination_library)
27
28
  raise ArgumentError.new("Invalid pagination library") unless pagination_library_valid?(pagination_library)
28
- @pagination_library = pagination_library.to_sym
29
+ @pagination_library = pagination_library
29
30
  end
30
31
 
31
32
  def default_loading_method=(default_loading_method)
32
33
  raise ArgumentError.new("Invalid method for eager loading") unless default_loading_method_valid?(default_loading_method)
33
- @default_loading_method = default_loading_method.to_sym
34
+ @default_loading_method = default_loading_method
34
35
  end
35
36
 
36
37
  private
@@ -48,11 +49,19 @@ module ActiveManageable
48
49
  end
49
50
 
50
51
  def default_loading_method_valid?(default_loading_method)
51
- option_valid?(LOADING_METHODS, default_loading_method)
52
+ symbol_option_valid?(LOADING_METHODS, default_loading_method)
52
53
  end
53
54
 
54
55
  def option_valid?(options, option)
55
- option.present? && options.include?(option.to_s.to_sym)
56
+ symbol_option_valid?(options, option) || module_option_valid?(option)
57
+ end
58
+
59
+ def symbol_option_valid?(options, option)
60
+ option.is_a?(Symbol) && options.include?(option.to_s.to_sym)
61
+ end
62
+
63
+ def module_option_valid?(option)
64
+ option.is_a?(Module)
56
65
  end
57
66
  end
58
67
  end
@@ -33,7 +33,7 @@ module ActiveManageable
33
33
  # the associations and options we cannot use the array extract_options! method
34
34
  # as this removes the last element in the array if it's a hash.
35
35
  #
36
- # For example :-
36
+ # For example:-
37
37
  # default_includes songs: :artist, loading_method: :preload, methods: :index
38
38
  # results in an argument value of :-
39
39
  # [{:songs=>:artist, :loading_method=>:preload, :methods=>:index}]
@@ -58,38 +58,36 @@ module ActiveManageable
58
58
  end
59
59
  end
60
60
 
61
- included do
62
- private
61
+ def default_includes(method: @current_method)
62
+ includes = defaults[:includes] || {}
63
+ associations = includes.dig(method.try(:to_sym), :associations) || includes.dig(:all, :associations)
64
+ associations.is_a?(Proc) ? instance_exec(&associations) : associations
65
+ end
63
66
 
64
- # Accepts either an array/hash of associations
65
- # or a hash with associations and loading_method keys
66
- # so it's possible to specify loading_method on a per request basis.
67
- # Uses associations and loading_method from opts
68
- # or defaults for the method or defaults for all methods
69
- # or configuration default loading_method.
70
- def includes(opts)
71
- unless opts.is_a?(Hash) && opts.key?(:associations)
72
- opts = {associations: opts}
73
- end
74
- associations = opts[:associations] || get_default_includes_associations
75
- if associations.present?
76
- loading_method = opts[:loading_method] || get_default_includes_loading_method
77
- @target = @target.send(loading_method, associations)
78
- else
79
- @target
80
- end
81
- end
67
+ def default_loading_method(method: @current_method)
68
+ includes = defaults[:includes] || {}
69
+ loading_method = includes.dig(method.try(:to_sym), :loading_method) || includes.dig(:all, :loading_method)
70
+ loading_method || ActiveManageable.configuration.default_loading_method
71
+ end
82
72
 
83
- def get_default_includes_associations
84
- includes = defaults[:includes] || {}
85
- associations = includes.dig(@current_method, :associations) || includes.dig(:all, :associations)
86
- associations.is_a?(Proc) ? instance_exec(&associations) : associations
87
- end
73
+ private
88
74
 
89
- def get_default_includes_loading_method
90
- includes = defaults[:includes] || {}
91
- loading_method = includes.dig(@current_method, :loading_method) || includes.dig(:all, :loading_method)
92
- loading_method || ActiveManageable.configuration.default_loading_method
75
+ # Accepts either an array/hash of associations
76
+ # or a hash with associations and loading_method keys
77
+ # so it's possible to specify loading_method on a per request basis.
78
+ # Uses associations and loading_method from opts
79
+ # or defaults for the method or defaults for all methods
80
+ # or configuration default loading_method.
81
+ def includes(opts)
82
+ unless opts.is_a?(Hash) && opts.key?(:associations)
83
+ opts = {associations: opts}
84
+ end
85
+ associations = opts[:associations] || default_includes
86
+ if associations.present?
87
+ loading_method = opts[:loading_method] || default_loading_method
88
+ @target = @target.send(loading_method, associations)
89
+ else
90
+ @target
93
91
  end
94
92
  end
95
93
  end
@@ -33,25 +33,23 @@ module ActiveManageable
33
33
  end
34
34
  end
35
35
 
36
- included do
37
- private
36
+ # Returns the default attribute values for the method
37
+ # from the class attribute that can contain a hash of attribute values
38
+ # or a lambda/proc to execute to return attribute values
39
+ def default_attribute_values(method: @current_method)
40
+ default_attributes = defaults[:attributes] || {}
41
+ attributes = default_attributes[method.try(:to_sym)] || default_attributes[:all] || {}
42
+ attributes = (instance_exec(&attributes) || {}) if attributes.is_a?(Proc)
43
+ attributes.with_indifferent_access
44
+ end
38
45
 
39
- # Returns attribute values to use in the new and create methods
40
- # consisting of a merge of the method attributes argument
41
- # and class defaults with the method argument taking precedence
42
- def attribute_values
43
- @attributes.is_a?(Hash) ? @attributes.reverse_merge(get_default_attribute_values) : @attributes
44
- end
46
+ private
45
47
 
46
- # Get the default attribute values for the method
47
- # from the class attribute that can contain a hash of attribute values
48
- # or a lambda/proc to execute to return attribute values
49
- def get_default_attribute_values
50
- default_attributes = defaults[:attributes] || {}
51
- attributes = default_attributes[@current_method] || default_attributes[:all] || {}
52
- attributes = (instance_exec(&attributes) || {}) if attributes.is_a?(Proc)
53
- attributes.with_indifferent_access
54
- end
48
+ # Returns attribute values to use in the new and create methods
49
+ # consisting of a merge of the method attributes argument
50
+ # and class defaults with the method argument taking precedence
51
+ def attribute_values
52
+ @attributes.is_a?(Hash) ? @attributes.reverse_merge(default_attribute_values) : @attributes
55
53
  end
56
54
  end
57
55
  end
@@ -19,23 +19,21 @@ module ActiveManageable
19
19
  end
20
20
  end
21
21
 
22
- included do
23
- private
22
+ # Returns the default order attributes from the class attribute
23
+ # that can contain an array of attribute names or name & direction strings
24
+ # or a lambda/proc to execute to return an array of attribute names
25
+ def default_order
26
+ defaults[:order].is_a?(Proc) ? instance_exec(&defaults[:order]) : defaults[:order]
27
+ end
24
28
 
25
- def order(attributes)
26
- @target = @target.order(get_order_attributes(attributes))
27
- end
29
+ private
28
30
 
29
- def get_order_attributes(attributes)
30
- attributes || get_default_order_attributes
31
- end
31
+ def order(attributes)
32
+ @target = @target.order(order_attributes(attributes))
33
+ end
32
34
 
33
- # Get the default order attributes from the class attribute
34
- # that can contain an array of attribute names or name & direction strings
35
- # or a lambda/proc to execute to return an array of attribute names
36
- def get_default_order_attributes
37
- defaults[:order].is_a?(Proc) ? instance_exec(&defaults[:order]) : defaults[:order]
38
- end
35
+ def order_attributes(attributes)
36
+ attributes || default_order
39
37
  end
40
38
  end
41
39
  end