Last active
May 14, 2019 08:52
-
-
Save sinsoku/b5b800570ec95ac4526ed973dfcd131f to your computer and use it in GitHub Desktop.
`lazy_find_by` returns AR instance that executes queries when attributes is needed.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
## Simple UseCase | |
user = User.lazy_find_by(id: 1, name: "foo") | |
#=> #<User id: 1, name: "foo", age: nil, created_at: nil, updated_at: nil> | |
user.id | |
#=> 1 | |
user.name | |
#=> "foo" | |
user.age | |
User Load (0.4ms) SELECT "users".* FROM "users" WHERE "users"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] | |
#=> 1 | |
## Use has_many | |
user_2 = User.lazy_find_by(id: 1) | |
user_2.posts.find_by(id: 1) | |
Post Load (0.3ms) SELECT "posts".* FROM "posts" WHERE "posts"."user_id" = ? AND "posts"."id" = ? LIMIT ? [["user_id", 1], ["id", 1], ["LIMIT", 1]] | |
#=> #<Post id: 1, user_id: 1, title: "bar", created_at: "2019-05-10 15:44:39", updated_at: "2019-05-10 15:44:39"> | |
user_3 = User.lazy_find_by(id: 1) | |
post = user_3.posts.create(title: "buz") | |
User Load (3.5ms) SELECT "users".* FROM "users" WHERE "users"."id" = ? LIMIT ? [["id", 1], ["LIMIT", 1]] | |
(0.1ms) begin transaction | |
Post Create (3.0ms) INSERT INTO "posts" ("user_id", "title", "created_at", "updated_at") VALUES (?, ?, ?, ?) [["user_id", 1], ["title", "buz"], ["created_at", "2019-05-10 17:12:06.418763"], ["updated_at", "2019-05-10 17:12:06.418763"]] | |
(1.5ms) commit transaction | |
#=> #<Post id: 4, user_id: 1, title: "buz", created_at: "2019-05-10 17:12:06", updated_at: "2019-05-10 17:12:06"> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# frozen_string_literal: true | |
module ActiveRecordLazyFindBy | |
STATE_METHOD_NAMES = %i[valid? new_record? persisted?].freeze | |
class << self | |
def module_for(klass, attributes) | |
lazy_attr_names = (klass.attribute_names - attributes.keys.map(&:to_s)).sort | |
key = [klass, lazy_attr_names] | |
cache[key] ||= build(lazy_attr_names) | |
end | |
def cache | |
@cache ||= {} | |
end | |
private | |
def build(attr_names) | |
lazy_method_names = attr_names.flat_map { |x| [x, "#{x}?", "#{x}="] } + STATE_METHOD_NAMES | |
Module.new do | |
lazy_method_names.each do |m| | |
define_method(m) do |*args| | |
unless @lazy_new_record | |
@lazy_new_record = true | |
reload | |
end | |
super(*args) | |
end | |
end | |
end | |
end | |
end | |
module Methods | |
def self.included(base) | |
base.extend ClassMethods | |
end | |
module ClassMethods | |
def lazy_find_by(attributes = {}) | |
mod = ActiveRecordLazyFindBy.module_for(self, attributes) | |
new(attributes).extend(mod) | |
end | |
end | |
end | |
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
class ApplicationRecord < ActiveRecord::Base | |
include ActiveRecordLazyFindBy::Methods | |
self.abstract_class = true | |
end |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment