<img src=“https://travis-ci.org/djonasson/symmetry.png?branch=master” alt=“Build Status” /> <img src=“https://gemnasium.com/djonasson/symmetry.png” alt=“Dependency Status” /> <img src=“https://codeclimate.com/github/djonasson/symmetry.png” alt=“Code Climate” /> <img src=“https://coveralls.io/repos/djonasson/symmetry/badge.png?branch=master” alt=“Coverage Status” /> <img src=“https://badge.fury.io/rb/symmetry.png” alt=“Gem Version” />
Symmetry gives you a simple way of creating symmetric has_and_belongs_to_many relationships (friends, neighbors, etc.) in your Active Record models.
Add it to your Gemfile:
gem "symmetry"
Install the migrations:
rails symmetry_engine:install:migrations db:migrate
Define a symmetric relationship:
class User < ApplicationRecord symmetric_relationship :friends end class Country < ApplicationRecord symmetric_relationship :neighbors, polymorphic_relationship_name: :neighborships end
Use it:
# User irb(main)> u = User.create(name: "Daniel") => #<User id: 1, name: "Daniel", ...> irb(main)> u.friends => [] irb(main)> u.friend_relationships => [] # Country irb(main)> c = Country.create(name: "Sweden") => #<Country id: 1, name: "Sweden", ...> irb(main)> c.neighbors << Country.create(name: "Norway") => [#<Country id: 2, name: "Norway", ...>] irb(main)> c.neighbors => [#<Country id: 2, name: "Norway", ...>] irb(main)> Country.find(2).neighbors => [#<Country id: 1, name: "Sweden", ...>] irb(main)> c.neighborships => [#<SymmetricRelationship id: 1, owner_id: 1, owner_type: "Country", relation_id: 2, relation_type: "Country", relationship_name: "neighbors" ...>, ...]
It is possible to define multiple symmetric relationships on the same model:
class Politician < ApplicationRecord symmetric_relationship :friends symmetric_relationship :enemies end irb(main)> p1 = Politician.create(name: 'A') => #<Politician id: 1, name: "A", ...> irb(main)> p2 = Politician.create(name: 'B') => #<Politician id: 2, name: "B", ...> irb(main)> p3 = Politician.create(name: 'C') => #<Politician id: 3, name: "C", ...> irb(main)> p1.friends => [] irb(main)> p1.enemies => [] irb(main)> p1.friends << p2 => [#<Politician id: 2, name: "B", ...>] irb(main)> p1.enemies << p3 => [#<Politician id: 3, name: "C", ...>] irb(main)> p1.friends.count => 1 irb(main)> p1.enemies.count => 1 irb(main)> p2.friends.count => 1 irb(main)> p2.enemies.count => 0