Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feature skip_preload #34

Merged
merged 3 commits into from Jul 21, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
2 changes: 2 additions & 0 deletions CHANGELOG.md
Expand Up @@ -2,6 +2,8 @@

## master

- [PR [#33](https://github.com/DmitryTsepelev/ar_lazy_preload/pull/34)] Feature skip_preload, allow turn automatic preload off ([@OuYangJinTing][])

## 0.3.1 (2020-07-10)

- [PR [#33](https://github.com/DmitryTsepelev/ar_lazy_preload/pull/33)] Don't do merge if there is nothing to merge ([@Earendil95][])
Expand Down
6 changes: 6 additions & 0 deletions README.md
Expand Up @@ -44,6 +44,12 @@ ArLazyPreload.config.auto_preload = true

After that there is no need to call `#lazy_preload` on the association, everything would be loaded lazily.

If you want to turn automatic preload off for a specific record, you can call `.skip_preload` before any associations method:

```ruby
users.first.skip_preload.posts # => SELECT * FROM posts WHERE user_id = ?
```

## Installation

Add this line to your application's Gemfile, and you're all set:
Expand Down
6 changes: 6 additions & 0 deletions lib/ar_lazy_preload/active_record/base.rb
Expand Up @@ -10,5 +10,11 @@ def self.included(base)
attr_accessor :lazy_preload_context

delegate :try_preload_lazily, to: :lazy_preload_context, allow_nil: true

def skip_preload
lazy_preload_context&.records&.delete(self)
self.lazy_preload_context = nil
self
end
end
end
4 changes: 2 additions & 2 deletions lib/ar_lazy_preload/active_record/collection_association.rb
Expand Up @@ -3,7 +3,7 @@
module ArLazyPreload
# ActiveRecord::CollectionAssociation patch with a hook for lazy preloading
module CollectionAssociation
# rubocop:disable Metrics/AbcSize
# rubocop:disable Metrics/AbcSize, Metrics/CyclomaticComplexity
def ids_reader
return super if owner.lazy_preload_context.blank?

Expand All @@ -16,6 +16,6 @@ def ids_reader
@association_ids ||= reader.map(&primary_key)
end
end
# rubocop:enable Metrics/AbcSize
# rubocop:enable Metrics/AbcSize, Metrics/CyclomaticComplexity
OuYangJinTing marked this conversation as resolved.
Show resolved Hide resolved
end
end
8 changes: 7 additions & 1 deletion spec/ar_lazy_preload/active_record/base_spec.rb
Expand Up @@ -3,9 +3,15 @@
require "spec_helper"

describe ArLazyPreload::Base do
describe "lazy_preload" do
describe "#lazy_preload" do
subject { ActiveRecord::Base }

it { is_expected.to respond_to(:lazy_preload) }
end

describe "#skip_preload" do
subject { User.new }

it { is_expected.to respond_to(:skip_preload) }
end
end
45 changes: 45 additions & 0 deletions spec/ar_lazy_preload/skip_preload_spec.rb
@@ -0,0 +1,45 @@
# frozen_string_literal: true

require "spec_helper"

describe "ArLazyPreload.skip_preload" do
let!(:user1) { create(:user) }
let!(:user2) { create(:user) }
let!(:user3) { create(:user) }

let!(:post1) { create(:post, user: user1) }
let!(:post2) { create(:post, user: user1) }
let!(:post3) { create(:post, user: user2) }

before(:each) { ArLazyPreload.config.auto_preload = true }

describe "#skip_preload" do
subject { User.all }

it "after skip preload, changed lazy preload context" do
subject.load.last.skip_preload
expect(subject.last.lazy_preload_context).to be(nil)
expect(subject.first.lazy_preload_context.records).not_to include(subject.last)
end

it "only load own association" do
subject.each do |user|
# SELECT "posts".* FROM "posts" WHERE "posts"."user_id" = ?
expect do
user.skip_preload.posts.load
end.to make_database_queries(matching: "\"posts\".\"user_id\" = ?")
end
end

it "loads excluded association" do
subject.load.last.skip_preload.posts.to_a
id_concat = subject[0..-2].map(&:id).join(", ")
question_concat = (["?"] * (subject.size - 1)).join(", ")
expect do
subject.first.posts.to_a
end.to make_database_queries(
matching: /\"user_id\" IN ([(#{id_concat})|(#{question_concat})])/
)
end
end
end