active_record_custom_preloader 0.2.2 → 0.3.0
Sign up to get free protection for your applications and to get access to all the features.
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
|