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.
- checksums.yaml +4 -4
- data/.github/workflows/ci.yml +23 -11
- data/.gitignore +1 -1
- data/.rubocop.yml +12 -19
- data/Appraisals +19 -10
- data/CHANGELOG.md +18 -0
- data/Gemfile.lock +179 -108
- data/README.md +81 -11
- data/active_manageable.gemspec +7 -7
- data/gemfiles/rails_7_0.gemfile +9 -2
- data/gemfiles/{rails_6_1.gemfile → rails_7_1.gemfile} +2 -2
- data/gemfiles/{rails_6_0.gemfile → rails_7_2.gemfile} +2 -2
- data/lib/active_manageable/authorization/cancancan.rb +10 -12
- data/lib/active_manageable/authorization/pundit.rb +10 -12
- data/lib/active_manageable/base.rb +16 -5
- data/lib/active_manageable/configuration.rb +16 -7
- data/lib/active_manageable/methods/auxiliary/includes.rb +28 -30
- data/lib/active_manageable/methods/auxiliary/model_attributes.rb +15 -17
- data/lib/active_manageable/methods/auxiliary/order.rb +12 -14
- data/lib/active_manageable/methods/auxiliary/scopes.rb +35 -28
- data/lib/active_manageable/methods/auxiliary/select.rb +11 -13
- data/lib/active_manageable/methods/auxiliary/unique_search.rb +19 -19
- data/lib/active_manageable/methods/create.rb +20 -5
- data/lib/active_manageable/methods/destroy.rb +22 -7
- data/lib/active_manageable/methods/edit.rb +17 -9
- data/lib/active_manageable/methods/index.rb +28 -26
- data/lib/active_manageable/methods/new.rb +14 -6
- data/lib/active_manageable/methods/show.rb +17 -9
- data/lib/active_manageable/methods/update.rb +28 -7
- data/lib/active_manageable/pagination/kaminari.rb +29 -9
- data/lib/active_manageable/search/ransack.rb +15 -17
- data/lib/active_manageable/version.rb +1 -1
- metadata +36 -28
- data/.rubocop_rails.yml +0 -201
- data/.rubocop_rspec.yml +0 -68
- 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
|
|
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;
|
|
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`.
|
|
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
|
|
data/active_manageable.gemspec
CHANGED
|
@@ -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
|
-
|
|
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", ">=
|
|
45
|
-
spec.add_dependency "activesupport", ">=
|
|
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"
|
|
51
|
+
spec.add_development_dependency "rake"
|
|
53
52
|
spec.add_development_dependency "appraisal"
|
|
54
|
-
spec.add_development_dependency "sqlite3"
|
|
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"
|
|
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
|
|
data/gemfiles/rails_7_0.gemfile
CHANGED
|
@@ -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: "../"
|
|
@@ -7,21 +7,19 @@ module ActiveManageable
|
|
|
7
7
|
module CanCanCan
|
|
8
8
|
extend ActiveSupport::Concern
|
|
9
9
|
|
|
10
|
-
|
|
11
|
-
private
|
|
10
|
+
private
|
|
12
11
|
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
12
|
+
def authorize(record:, action: nil)
|
|
13
|
+
action ||= @current_method
|
|
14
|
+
current_ability.authorize!(action, record)
|
|
15
|
+
end
|
|
17
16
|
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
17
|
+
def authorization_scope
|
|
18
|
+
model_class.accessible_by(current_ability)
|
|
19
|
+
end
|
|
21
20
|
|
|
22
|
-
|
|
23
|
-
|
|
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
|
-
|
|
11
|
-
private
|
|
10
|
+
private
|
|
12
11
|
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
12
|
+
def authorize(record:, action: nil)
|
|
13
|
+
action ||= authorize_action
|
|
14
|
+
::Pundit.authorize(current_user, record, action)
|
|
15
|
+
end
|
|
17
16
|
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
17
|
+
def authorization_scope
|
|
18
|
+
::Pundit.policy_scope(current_user, model_class)
|
|
19
|
+
end
|
|
21
20
|
|
|
22
|
-
|
|
23
|
-
|
|
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
|
-
|
|
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
|
-
|
|
12
|
-
|
|
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.
|
|
130
|
-
caller_locations[1..].find { |location| location.
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
-
|
|
52
|
+
symbol_option_valid?(LOADING_METHODS, default_loading_method)
|
|
52
53
|
end
|
|
53
54
|
|
|
54
55
|
def option_valid?(options, option)
|
|
55
|
-
|
|
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
|
-
|
|
62
|
-
|
|
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
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
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
|
-
|
|
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
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
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
|
-
|
|
37
|
-
|
|
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
|
-
|
|
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
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
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
|
-
|
|
23
|
-
|
|
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
|
-
|
|
26
|
-
@target = @target.order(get_order_attributes(attributes))
|
|
27
|
-
end
|
|
29
|
+
private
|
|
28
30
|
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
31
|
+
def order(attributes)
|
|
32
|
+
@target = @target.order(order_attributes(attributes))
|
|
33
|
+
end
|
|
32
34
|
|
|
33
|
-
|
|
34
|
-
|
|
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
|