No commit activity in last 3 years
No release in over 3 years
Annotate ActiveRecord relations objects with custom data, allowing metadata on relations that can be used to customize code
2005
2006
2007
2008
2009
2010
2011
2012
2013
2014
2015
2016
2017
2018
2019
2020
2021
2022
2023
2024
 Dependencies

Development

~> 1.7
>= 0
~> 10.0
~> 3.1.0
~> 1.3

Runtime

 Project Readme

RelationsAnnotations

Annotate ActiveRecord relations objects with custom data, allowing metadata on relations that can be used to customize code.

Installation

Add this line to your application's Gemfile:

gem 'activerecord-relations_annotations', '~> 0.0.1'

And then execute:

$ bundle

Or install it yourself as:

$ gem install activerecord-relations_annotations

Usage

Not the greatest example, but gives you a rough idea:

class User < ActiveRecord::base
  include ActiveRecord::RelationsAnnotations
end

users = User.where.not(email: nil)
with_email_users = users.annotate(:with_email? => true)
without_email_users = users.annotate(:with_email? => false)

if with_email_users.annotations.with_email?
  # Do some stuff
end

unless without_email_users.annotations.with_email?
  # Do other stuff on this group of users
end

Annotations can also be accessed in a hash-fashion, like on OpenStruct:

users = User.where(email: 'foo').annotate(foo: 'bar')

users.annotations[:foo] # => 'bar'
users.annotations[:something] # => nil

Documentation

#annotate(**values) accepts a hash, values are merged into the annotations OpenStruct, it returns a new ActiveRecord::Relation based on the one is called on. If it's called as the first method (directly on model class), it behaves like it's called on all method.

annotations method returns an OpenStruct with all annotations set on the relation.

annotated method should not be used, basically ensures we are in an ActiveRecord::Relation and ensures the annotations OpenStruct exists, so even in case it's called, it won't do any damage.

Features

Chainable

User.where.not(email: 'foo').
  annotate(testme: 123, blah: 'hi').
  annotate(foo: 'bar').
  where(something: 'else').
  annotations
# => <OpenStruct testme=123, blah='hi', something='else'>

Always returns an OpenStruct

User.annotations
# => <OpenStruct>
User.where.not(email: 'foo').annotations
# => <OpenStruct>

It always creates a relation

User.annotate(foo: 'bar').class
# => User::ActiveRecord_Relation

Gotchas

When you call methods on relations, they create new values, much like map for array, which creates a new array. This means the following:

tmp = User.where.name(email: 'foo')

tmp2 = tmp.annotate(bar: 'baz')

tmp.annotations # => <OpenStruct>
tmp2.annotations # => <OpenStruct bar='baz'>

It shouldn't be a problem, though, because it's standard ActiveRecord::Relation behavior.

How it works

Functionality is simple, the only hack is that when annotate, annotated and annotations are called, a instance variable is created (if missing), called @_annotations and it's used to read values, through instance_variable_set and instance_variable_get.

Contributing

  1. Fork it ( https://github.com/Fire-Dragon-DoL/activerecord-relations_annotations/fork )
  2. Create your feature branch (git checkout -b my-new-feature)
  3. Commit your changes (git commit -am 'Add some feature')
  4. Push to the branch (git push origin my-new-feature)
  5. Create a new Pull Request