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
endAnnotations 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] # => nilDocumentation
#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_RelationGotchas
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
- Fork it ( https://github.com/Fire-Dragon-DoL/activerecord-relations_annotations/fork )
- Create your feature branch (
git checkout -b my-new-feature) - Commit your changes (
git commit -am 'Add some feature') - Push to the branch (
git push origin my-new-feature) - Create a new Pull Request