active_record_custom_preloader 0.2.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
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 99ce25238e6af5cdf1e5ded9fb5a20cb538eea30
|
4
|
+
data.tar.gz: 6e51a7f912349423c01112afd78b06f0a59806a4
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 4f732ec7ac341a988cfbe4163211a0f85176980c31b9581641d5ad9ace75f045a9f021837f2329e7dd7c0748ee97b132825ddc4364066878f319e49dcf152cc1
|
7
|
+
data.tar.gz: af9a8f4e709aac03f81b250ac96a4f61289c640e59127dfd5a092a81805e5ffa82ba8c24e77c49b59ffca9aa9a369c94d77f4019e2d0e80bdb349237aa2ef120
|
data/README.md
CHANGED
@@ -4,12 +4,22 @@ custom preloader for ActiveRecord model
|
|
4
4
|
|
5
5
|
## Installation
|
6
6
|
|
7
|
-
Add this line to your application's Gemfile
|
7
|
+
Add this line to your application's `Gemfile`:
|
8
8
|
|
9
9
|
```ruby
|
10
10
|
gem 'active_record_custom_preloader'
|
11
11
|
```
|
12
12
|
|
13
|
+
if you use Rails you should require `railtie.rb` file
|
14
|
+
like this in `config/application.rb`:
|
15
|
+
```ruby
|
16
|
+
require 'active_record_custom_preloader/railtie'
|
17
|
+
```
|
18
|
+
or like this in `Gemfile`
|
19
|
+
```ruby
|
20
|
+
gem 'active_record_custom_preloader', require: 'active_record_custom_preloader/railtie'
|
21
|
+
```
|
22
|
+
|
13
23
|
And then execute:
|
14
24
|
|
15
25
|
$ bundle
|
@@ -25,7 +35,10 @@ class Person < ActiveRecord::Base
|
|
25
35
|
add_custom_loader :_stats, class_name: 'StatsPreloader'
|
26
36
|
end
|
27
37
|
|
28
|
-
class
|
38
|
+
class ApplicationPreloader < ActiveRecordCustomPreloader::Preloader
|
39
|
+
end
|
40
|
+
|
41
|
+
class StatsPreloader < ApplicationPreloader
|
29
42
|
def preload(records)
|
30
43
|
ids = records.map(&:id)
|
31
44
|
values = CustomApi.fetch_stats_for(ids)
|
@@ -4,6 +4,7 @@ require 'active_record_custom_preloader/preload_with_options'
|
|
4
4
|
require 'active_record_custom_preloader/associations_preloader'
|
5
5
|
require 'active_record_custom_preloader/model_patch'
|
6
6
|
require 'active_record_custom_preloader/relation_patch'
|
7
|
+
require 'active_record_custom_preloader/with_multiple_foreign_keys_loading'
|
7
8
|
|
8
9
|
module ActiveRecordCustomPreloader
|
9
10
|
class Error < StandardError
|
@@ -0,0 +1,94 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
require 'active_support/concern'
|
3
|
+
|
4
|
+
# Usage example:
|
5
|
+
#
|
6
|
+
# class Employee < ApplicationRecord
|
7
|
+
# # columns: id, name, department_id, position_id
|
8
|
+
# add_custom_loader :_contract, class_name: 'EmployeeContractPreloader'
|
9
|
+
# end
|
10
|
+
#
|
11
|
+
# class Contract < ApplicationRecord
|
12
|
+
# # columns: id, text, employee_department_id, position_id
|
13
|
+
# end
|
14
|
+
#
|
15
|
+
# class EmployeeContractPreloader < ActiveRecordCustomPreloader::Preloader
|
16
|
+
# include ActiveRecordCustomPreloader::WithMultipleForeignKeysLoading
|
17
|
+
# self.model_class_name = 'Contract'
|
18
|
+
# self.association_foreign_keys_names = [:employee_department_id, :position_id]
|
19
|
+
#
|
20
|
+
# def record_foreign_keys(record)
|
21
|
+
# [record.department_id, record.position_id]
|
22
|
+
# end
|
23
|
+
# end
|
24
|
+
#
|
25
|
+
module ActiveRecordCustomPreloader
|
26
|
+
module WithMultipleForeignKeysLoading
|
27
|
+
extend ActiveSupport::Concern
|
28
|
+
|
29
|
+
included do
|
30
|
+
# should be true for has_many and false for has_one.
|
31
|
+
# [optional] (default false)
|
32
|
+
class_attribute :to_many, instance_writer: false
|
33
|
+
self.to_many = false
|
34
|
+
|
35
|
+
# model class of association records
|
36
|
+
# [required]
|
37
|
+
class_attribute :model_class_name, instance_writer: false
|
38
|
+
|
39
|
+
# Names of foreign keys which link association record to parent record.
|
40
|
+
# Should returns array of key names for association record for query.
|
41
|
+
# [required]
|
42
|
+
class_attribute :association_foreign_keys_names, instance_writer: false
|
43
|
+
|
44
|
+
private :fetch_association
|
45
|
+
end
|
46
|
+
|
47
|
+
# association table is queried by return value of this method.
|
48
|
+
# returns array of keys for parent record to match association record
|
49
|
+
def record_foreign_keys(parent_record)
|
50
|
+
association_foreign_keys(parent_record)
|
51
|
+
end
|
52
|
+
|
53
|
+
# association records are grouped by return value of this method.
|
54
|
+
# it should match
|
55
|
+
# returns array of keys for association record to match parent record
|
56
|
+
def association_foreign_keys(assoc_record)
|
57
|
+
association_foreign_keys_names.map { |name| assoc_record.public_send(name) }
|
58
|
+
end
|
59
|
+
|
60
|
+
# returns associations for provided parent_record.
|
61
|
+
# array for has_many and model or nil for has_one.
|
62
|
+
def associations_by_record(grouped_associations, parent_record)
|
63
|
+
associations = grouped_associations[record_foreign_keys(parent_record)]
|
64
|
+
to_many ? associations || [] : associations&.first
|
65
|
+
end
|
66
|
+
|
67
|
+
# default scope for association records.
|
68
|
+
# you can override it for example to preload some values to association records.
|
69
|
+
def associations_scope
|
70
|
+
model_class_name.constantize.all
|
71
|
+
end
|
72
|
+
|
73
|
+
def fetch_association(parent_records)
|
74
|
+
keys = parent_records.map(&method(:record_foreign_keys))
|
75
|
+
condition_part = association_foreign_keys_names.map { |name| "#{name} = ?" }.join(' AND ')
|
76
|
+
conditions = []
|
77
|
+
keys.size.times { conditions.push(condition_part) }
|
78
|
+
condition_sql = conditions.map { |condition| "(#{condition})" }.join(' OR ')
|
79
|
+
condition_bindings = keys.flatten
|
80
|
+
return associations_scope.none if condition_sql.blank? || condition_bindings.empty?
|
81
|
+
associations = associations_scope.where(condition_sql, *condition_bindings).to_a
|
82
|
+
associations.group_by(&method(:association_foreign_keys))
|
83
|
+
end
|
84
|
+
|
85
|
+
def preload(parent_records)
|
86
|
+
grouped_associations = fetch_association(parent_records)
|
87
|
+
parent_records.each do |parent_record|
|
88
|
+
value = associations_by_record(grouped_associations, parent_record)
|
89
|
+
parent_record._set_custom_preloaded_value(name, value)
|
90
|
+
end
|
91
|
+
end
|
92
|
+
|
93
|
+
end
|
94
|
+
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: active_record_custom_preloader
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.3.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Denis Talakevich
|
@@ -105,6 +105,7 @@ files:
|
|
105
105
|
- lib/active_record_custom_preloader/railtie.rb
|
106
106
|
- lib/active_record_custom_preloader/relation_patch.rb
|
107
107
|
- lib/active_record_custom_preloader/version.rb
|
108
|
+
- lib/active_record_custom_preloader/with_multiple_foreign_keys_loading.rb
|
108
109
|
homepage: https://github.com/senid231/active_record_custom_preloader
|
109
110
|
licenses:
|
110
111
|
- MIT
|