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: ebc260ca02c7f72a2c65f2cb594735d982482108
4
- data.tar.gz: 473f45b86356872c382adfde7fa35f7229e5ec38
3
+ metadata.gz: 99ce25238e6af5cdf1e5ded9fb5a20cb538eea30
4
+ data.tar.gz: 6e51a7f912349423c01112afd78b06f0a59806a4
5
5
  SHA512:
6
- metadata.gz: 38dd285e78ce11f4d9648db79b56b95c196916bf7b5c7412d1e81ff6eb7c0bd2ad5f888a215be3e96b54e35afae1258f0bc626eb0452bacf00ea06f0a7b96a75
7
- data.tar.gz: f4b515d22b3a83e74a57e55ac6ceaf7acc0212e09f27856f3c8c90df9a48c073444deb5e48526e49dfd80fed81ae75c3035c95dac9ed8e3ea06d5c24b6f326c3
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 StatsPreloader < ActiveRecordCustomerPreloader::Preloader
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
@@ -1,3 +1,3 @@
1
1
  module ActiveRecordCustomPreloader
2
- VERSION = '0.2.2'
2
+ VERSION = '0.3.0'
3
3
  end
@@ -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.2.2
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