Created
November 9, 2017 18:10
-
-
Save wojtha/05f26f0a45ae260ab555396d89e16136 to your computer and use it in GitHub Desktop.
ActiveRecord::Finder implementation with chainable scopes!
This file contains hidden or 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
module ActiveRecord | |
module Finder | |
module Scope | |
extend ActiveSupport::Concern | |
attr_reader :relation | |
def initialize(relation) | |
@relation = relation | |
end | |
def default_scope | |
relation.clone | |
end | |
def to_relation | |
relation.clone | |
end | |
module ClassMethods | |
def scope(name, body) | |
unless body.respond_to?(:call) | |
raise ArgumentError, "The scope body needs to be callable." | |
end | |
if respond_to?(name, true) | |
raise ArgumentError, "Creating scope :#{name}. Overwriting existing method #{self.name}.#{name}." | |
end | |
if body.respond_to?(:to_proc) | |
define_method(name) do |*args| | |
scope = default_scope.scoping { relation.model.instance_exec(*args, &body) } | |
self.class.new(scope || default_scope) | |
end | |
else | |
define_method(name) do |*args| | |
scope = default_scope.scoping { body.call(*args) } | |
self.class.new(scope || default_scope) | |
end | |
end | |
end | |
def private_scope(name, body) | |
scope(name, body) | |
private name | |
end | |
alias_method :pscope, :private_scope | |
end | |
end | |
module Model | |
extend ActiveSupport::Concern | |
include ActiveRecord::Finder::Scope | |
def initialize(relation = nil) | |
super(relation || self.class.model.all) | |
end | |
module ClassMethods | |
def finder_for(model) | |
@model = model | |
end | |
def model | |
@model | |
end | |
end | |
end | |
end | |
end | |
class TopicFinder | |
include ActiveRecord::Finder::Model | |
finder_for Topic | |
def list_active_for_owned_by(owner) | |
active.owned_by(owner).relation | |
end | |
def list_inactive_for_owned_by(owner) | |
inactive.owned_by(owner).relation | |
end | |
private_scope :active, -> { where(archived: false) } | |
private_scope :inactive, -> { where(archived: true) } | |
private_scope :owned_by, ->(owner) { where(owner_id: owner.id, owner_type: owner.class.to_s) } | |
end |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment