Skip to content

Instantly share code, notes, and snippets.

@elithecho
Created June 29, 2021 02:39
Show Gist options
  • Save elithecho/955120177e499b769cd7f994cb49dd39 to your computer and use it in GitHub Desktop.
Save elithecho/955120177e499b769cd7f994cb49dd39 to your computer and use it in GitHub Desktop.
Bool At Rails Lazy bugger
module BoolAt
extend ActiveSupport::Concern
class_methods do
# Defines a bool_at DSL
# allows setting true false on a virtual attribute
# and maps to attr_at
def bool_at(*attrs)
attrs.each do |attr|
at_attribute = "#{attr}_at"
at_setter = "#{attr}_at="
setter = "#{attr}="
predicate = "#{attr}?"
attribute attr, :boolean, default: false
after_initialize do
self[attr] = send(attr)
end
# Changes dirty state in virtual attribute
define_method setter do |value|
super(value)
send(at_setter, self[attr] ? Time.current : nil)
end
define_method attr do
send(at_attribute).present? if respond_to?(at_attribute)
end
define_method at_setter do |value|
self[attr] = value.present?
super(value)
end
alias_method predicate, attr
scope attr, -> { where("#{table_name}.#{attr}_at IS NOT NULL") }
scope :"not_#{attr}", -> { where("#{table_name}.#{attr}_at IS NULL") }
scope :"order_#{attr}", -> { order("#{table_name}.#{attr}_at DESC") }
scope :"reverse_#{attr}", -> { order("#{table_name}.#{attr}_at ASC") }
end
end
end
end
require "rails_helper"
class UserDummy < ApplicationRecord
self.table_name = "users"
attribute :marked_at, :datetime
bool_at :marked, :created
end
RSpec.describe BoolAt do
let(:user) { UserDummy.new }
describe "setter" do
it "sets time_at on attribute" do
user.marked = true
expect(user.marked_at).not_to be_nil
expect(user.marked_at).to be_a(Time)
end
it "receives form input and cancels" do
user.marked_at = Time.current
user.marked = "0"
expect(user.marked_at).to be_nil
expect(user.marked?).to be false
end
end
describe "predicate" do
context "when bool_at is nil" do
it { expect(user.marked?).to be false }
end
context "when bool_at is set" do
before { user.marked = true }
it { expect(user.marked?).to be true }
end
end
describe "alias" do
it "sets alias on predicate as getter" do
user.marked = true
expect(user.marked?).to be true
expect(user.marked_at).not_to be_nil
end
end
describe "scope" do
it "sets query scope for attribute" do
expect(UserDummy.respond_to?(:marked)).to be true
expect(UserDummy.respond_to?(:not_marked)).to be true
end
end
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment