Rubysh neo4j REST API for Rails or as standalone library
Fetching latest commit…
Cannot retrieve the latest commit at this time.
Failed to load latest commit information.

Morpheus - the power of neo4j in easy Ruby library

This gem gives you a way of using the REST API of neo4j graph database.

The main goals and differences with other libraries are:

  • It doesn't try to mimic ActiveRecord or ORM library as the concepts are different.
  • It forces you to think in terms of graph database, still preserving most of the conventions and semantics from Rails.
  • It is compatible with ActiveModel and can be used in Rails 3 easily.
  • Ruby DSL for node traversal and querying (with ability to fallback to raw API).
  • Automatic batching whenever possible for optimal performance.
  • Non-blocking operations.
  • It is not just a wrapper over the REST API but rather comprehensive tool to leverage Ruby as much as possible.
  • It can be used as standalone gem or as part of the Rails app.
  • Allow to transparently reuse the code on either client or server (via extensions mechanism) - maybe too ambitious, but why not?!


With Rails

  1. Add gem 'morpheus' to the Gemfile and bundle install.
  2. Run the generator: bundle exec rails g morpheus:install.


Just require the gem: require 'morpheus'. Make sure it is installed in your system gems or with bundler.

Usage by Examples

Simple standalone

require 'morpheus'

class User < Morpheus::Base
  # or if you don't want to inherit:
  # include Morpheus::Node
  relates_to :user, :as => :supervisor

db = # Will use the default settings

me = db, :name => 'Dmytrii', :email => ''! me # This creates the graph: ROOT-users->me

me_again = db.users.first

me == me_again # => true

# Set the properties on the relationship
boss = db, name: 'Seve'
me.supervisor = me
me.supervisor ????? # me.

In the future examples I'll skip boilerplate code such as initiating db, requiring this gem etc. Let me know if something isn't obvious from the context.

CRUD (can be used with Rails controllers)

# Create:
# attach it to the path ROOT-users->User db, :name => 'Dmytrii', :email => '' # => true
# or if you want the node to exist in vacuum:
User.create db, :name => 'Dmytrii', :email => '' # => true

# Read:
user = db.fetch User, 123 # instance of User

# Update:
user.twitter = '@dnagir' # true
user.update_attributes :twitter => '@dnagir'

# Destroy:
user.destroy # true


class User < Morpheus::NodeBase
  before_save :become_human
  before_save do
  before_save :become_human,     :on => :create
  before_save :become_human,     :on => [:create, :udpate]
  before_validate :become_human

  def become_human
    # This will be called multiple times
    self.human = true

Relationships - one-to-one

class Person < Morpheus::NodeBase
  relates_to :address, :as => :workplace # specify `:name => :office` if accessor method is different from :workplace

class Address < Morpheus::NodeBase

# This assumes the graph: `Person<-workplace->Address` 

me = db
office = db

me.workplace = office

Relationships - one-to-many

class Person < Morpheus::NodeBase
  relates_to_many :addresses, :as => :visited

class Address < Morpheus::NodeBase

# This assumes sub-graph `Person-visited->Address`

me = db
museum = db
park = db

me.visited << museum << park

Relationships - many-to-many

class Person < Morpheus::NodeBase
  relates_to_many :addresses :as => :visited

class Address < Morpheus::NodeBase
  related_to_many :people, :as => :visited

# This assumes sub-graph `Person<-visited->Address`

he = db
she = db
museum = db
park = db

he.visited << museum << park
she.visited << museum

museum.visited # [he, she]
park.visited # [he]


The traversal API available uses pure Ruby syntax and chooses the best suitable query language automatically (is it a prophet or what?).

  • Every method call (except select or similar internal methods) defines the traversing relationship.
  • Every block near the method call defines a condition on the end-side node of the relationship.
  • Every where clause applied defines a condition on a relationship.
  • Query must end with: select call with a block of values returned.


# Find all users who are liked

# All employees of the company with ID=123

# All employees of the existing company object

# All my friends that that have 'A' in the name and like somebody
me.query.friend{ name =~ /A/ } { friend }

# All my friends and all of their friends and all of their friends with the friendship longer than 1 year
me.query.friend([1..2]).where(started >= 1.year_ago).select

# If everything fails, use Cypher
db.query(:cypher).map_to(User).select("START s=node(0) MATCH s-[:users]->()-[:likes]->u RETURN u")



Rake tasks


Rails Generators


  • install
  • model
  • controller
  • scaffold

Non-Blocking Operations

By default all the requests will be dispatched asynchronously and the execution will not block. This means that you can execute multiple independent request in parallel without any changes to your code.

If you will access a data that hasn't yet been fetched, the current thread will be blocked until the results will be returned.

This means that you can do the following:

me = db.fetch User, 123
he = db.fetch User, 345

And the 2 requests will be executed in parallel (thus will take almost twice less time overall). The execution will only block when you access any data ( until the response will have been processed.

TBD: Exmplain how to configure

Additional Utilities


  • FactoryGirl
  • inherited_resources
  • cancan
  • Authlogic
  • Auditor
  • Automatic timestamps
  • DatabaseCleaner


  • neography - simple REST wrapper. Provides Node/Relationship classes for easy use. Well maintained.
  • neology - wraps REST in models. Uses neography internally. Seems a bit forgotten and not maintained well (specs fail).
  • architect4r - ActiveRecord-like API with the only query language being Cypher. Not sure how well it's maintained (but specs fail).