smart_preloads 0.0.1 → 0.1.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/README.md +25 -6
- data/VERSION +1 -1
- data/lib/smart_preloads/item.rb +15 -14
- data/lib/smart_preloads/list.rb +13 -1
- data/smart_preloads.gemspec +3 -3
- data/spec/smart_preloads_spec.rb +31 -0
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 18f4e3190dc51950fb7a67eb68be6e2f9d8b86a4
|
4
|
+
data.tar.gz: f47c16e997076ce9041616ae243d50974b4a57be
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 60e9e6f7c3fbc8da1e845ab31ef6e74ca7fca4bc4ca48dd40d43fb303374abea9426bd43ed9b825fce77243709071c1f151cc44f626b94d89884f579368dad39
|
7
|
+
data.tar.gz: b3ca7004e8f80ba53a1cea14985767cd210e93d61df45e9ce4b8c525a4252c6d2057c66e0665663610b4c1780ac4be3b7c14082b2e1d76ad773e16c55c4aa662
|
data/README.md
CHANGED
@@ -5,7 +5,15 @@ when you do not have control over which associations are going to be used by
|
|
5
5
|
the view, like when you provide users customizable views with
|
6
6
|
[Liquid](https://github.com/chamnap/liquid-rails).
|
7
7
|
|
8
|
-
##
|
8
|
+
## Installation
|
9
|
+
|
10
|
+
You can use `gem install smart_preloads` to install it manually or use Bundler:
|
11
|
+
|
12
|
+
```ruby
|
13
|
+
gem 'smart_preloads'
|
14
|
+
```
|
15
|
+
|
16
|
+
## Usage
|
9
17
|
|
10
18
|
You have to call `smart_preloads` at the end of your association. This will
|
11
19
|
generate a smart list of items that will load associations **if and when**
|
@@ -39,13 +47,24 @@ end
|
|
39
47
|
#=> SELECT "categories".* FROM "categories" WHERE "categories"."id" IN (1, 2)
|
40
48
|
```
|
41
49
|
|
42
|
-
##
|
50
|
+
## How it Works
|
43
51
|
|
44
|
-
|
52
|
+
In order for it to work, `smart_preloads` has a custom list class
|
53
|
+
(`SmartPreloads::List`) and a custom item class for each item in a list
|
54
|
+
(`SmartPreloads::Item`).
|
45
55
|
|
46
|
-
|
47
|
-
|
48
|
-
|
56
|
+
The List class allows detecting when the collection
|
57
|
+
is really used (iterated) so only then the associations will be detected and
|
58
|
+
mokey patched in place. This is needed so whenever a call to an association
|
59
|
+
is made it will be loaded, even from calls from within the object itself.
|
60
|
+
|
61
|
+
The Item class monkey patches all association methods in the objects loaded
|
62
|
+
to intercept the calls. The monkey patch is **in place**, not global. Only
|
63
|
+
the objects in the `smart_preloads` collection will be monkey patched.
|
64
|
+
|
65
|
+
Note that when you call `Author.all.smart_preloads.first` you will **not**
|
66
|
+
have an instance of `Author`. Instead, you will have an instance of
|
67
|
+
`SmartPreloads::Item` that delegates calls to the original `Author` object.
|
49
68
|
|
50
69
|
## Contributing
|
51
70
|
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
0.0
|
1
|
+
0.1.0
|
data/lib/smart_preloads/item.rb
CHANGED
@@ -3,23 +3,24 @@ module SmartPreloads
|
|
3
3
|
def initialize(record, loader: nil)
|
4
4
|
super(record)
|
5
5
|
@loader = loader || Loader.new([record])
|
6
|
+
_override_associations
|
7
|
+
end
|
6
8
|
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
end
|
9
|
+
def _override_associations
|
10
|
+
__getobj__.class.reflections.each do |key, association|
|
11
|
+
body = nil
|
12
|
+
loader = @loader
|
13
|
+
if %i(has_many has_and_belongs_to_many).include?(association.macro)
|
14
|
+
body = lambda do
|
15
|
+
List.new(super(), loader: loader.nested(key.to_sym))
|
16
|
+
end
|
17
|
+
else
|
18
|
+
body = lambda do
|
19
|
+
loader.load(key.to_sym)
|
20
|
+
super()
|
20
21
|
end
|
21
|
-
define_method(key, &body)
|
22
22
|
end
|
23
|
+
__getobj__.define_singleton_method(key, &body)
|
23
24
|
end
|
24
25
|
end
|
25
26
|
end
|
data/lib/smart_preloads/list.rb
CHANGED
@@ -9,7 +9,11 @@ module SmartPreloads
|
|
9
9
|
|
10
10
|
def each
|
11
11
|
loaded_collection.each do |resource|
|
12
|
-
|
12
|
+
if resource.is_a?(Item)
|
13
|
+
yield resource
|
14
|
+
else
|
15
|
+
yield Item.new(resource, loader: @loader)
|
16
|
+
end
|
13
17
|
end
|
14
18
|
end
|
15
19
|
|
@@ -21,6 +25,14 @@ module SmartPreloads
|
|
21
25
|
to_a.size
|
22
26
|
end
|
23
27
|
|
28
|
+
def +(other)
|
29
|
+
to_a + other.to_a
|
30
|
+
end
|
31
|
+
|
32
|
+
def [](idx)
|
33
|
+
to_a[idx]
|
34
|
+
end
|
35
|
+
|
24
36
|
protected
|
25
37
|
|
26
38
|
def loaded_collection
|
data/smart_preloads.gemspec
CHANGED
@@ -2,16 +2,16 @@
|
|
2
2
|
# DO NOT EDIT THIS FILE DIRECTLY
|
3
3
|
# Instead, edit Jeweler::Tasks in Rakefile, and run 'rake gemspec'
|
4
4
|
# -*- encoding: utf-8 -*-
|
5
|
-
# stub: smart_preloads 0.0
|
5
|
+
# stub: smart_preloads 0.1.0 ruby lib
|
6
6
|
|
7
7
|
Gem::Specification.new do |s|
|
8
8
|
s.name = "smart_preloads".freeze
|
9
|
-
s.version = "0.0
|
9
|
+
s.version = "0.1.0"
|
10
10
|
|
11
11
|
s.required_rubygems_version = Gem::Requirement.new(">= 0".freeze) if s.respond_to? :required_rubygems_version=
|
12
12
|
s.require_paths = ["lib".freeze]
|
13
13
|
s.authors = ["Diego Aguir Selzlein".freeze]
|
14
|
-
s.date = "2017-05-
|
14
|
+
s.date = "2017-05-26"
|
15
15
|
s.description = "Avoid N + 1 queries without having to worry about it at all!".freeze
|
16
16
|
s.email = "diegoselzlein@gmail.com".freeze
|
17
17
|
s.extra_rdoc_files = [
|
data/spec/smart_preloads_spec.rb
CHANGED
@@ -12,6 +12,10 @@ class Book < ActiveRecord::Base
|
|
12
12
|
belongs_to :author
|
13
13
|
belongs_to :category
|
14
14
|
has_many :tags, as: :taggable
|
15
|
+
|
16
|
+
def author_name
|
17
|
+
author.try!(:name)
|
18
|
+
end
|
15
19
|
end
|
16
20
|
|
17
21
|
class Tag < ActiveRecord::Base
|
@@ -78,4 +82,31 @@ describe 'SmartPreloads' do
|
|
78
82
|
expect(list.first.books.first.association(:category)).to be_loaded
|
79
83
|
expect(list.last.books.first.association(:category)).to be_loaded
|
80
84
|
end
|
85
|
+
|
86
|
+
it 'supports concatenation' do
|
87
|
+
Book.create!(name: 'Rework')
|
88
|
+
Book.create!(name: 'Lean Startup')
|
89
|
+
Author.create!(books: [Book.first])
|
90
|
+
Author.create!(books: [Book.last])
|
91
|
+
|
92
|
+
list = Book.all.smart_preloads + Author.all.smart_preloads
|
93
|
+
|
94
|
+
list[2].books.to_a
|
95
|
+
expect(list[3].association(:books)).to be_loaded
|
96
|
+
|
97
|
+
list.first.author
|
98
|
+
expect(list[1].association(:author)).to be_loaded
|
99
|
+
end
|
100
|
+
|
101
|
+
it 'works with internal methods' do
|
102
|
+
a1 = Author.create!(name: 'John')
|
103
|
+
a2 = Author.create!(name: 'Doe')
|
104
|
+
Book.create!(name: 'Rework', author: a1)
|
105
|
+
Book.create!(name: 'Lean Startup', author: a2)
|
106
|
+
|
107
|
+
list = Book.all.smart_preloads
|
108
|
+
|
109
|
+
list.first.author_name
|
110
|
+
expect(list[1].association(:author)).to be_loaded
|
111
|
+
end
|
81
112
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: smart_preloads
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0
|
4
|
+
version: 0.1.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Diego Aguir Selzlein
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2017-05-
|
11
|
+
date: 2017-05-26 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rspec
|