Neo4j.rb 1.0.0 and Rails 3

In the last three years I have together with several other contributors been developing the JRuby wrapper Neo4j.rb for the graph database Neo4j.
I believe that a graph database such as Neo4j and the Ruby language is a perfect match since they share the same dynamic nature, like duck typing, no schemas and no static compile time limitations.
The Neo4j JRuby wrapper has today reached version 1.0.0 and I think it now can be used in production.
It has support for things like online backup, high availability clustering, migrations, monitoring which is needed when running an application in a production environment.

Neo4j is usually used in graph related domains like: recommendation engine, social networks, product trees, routing.
In this blog I will show that Neo4j can also be used as an Active Record replacement.
You can compare the Rails 3/Neo4j example below with “How to Create a Blog from Scratch Using Ruby on Rails” which instead uses Rails 2 and ActiveRecord.

Neo4j.rb Architecture

The neo4j.rb consists of a three layers API:

  • Layer 1. For interacting with the basic building blocks of the graph database (node, properties and relationship), see Neo4j::Node and Neo4j::Relationship classes.
  • Layer 2. A binding API to Ruby objects, see Neo4j::NodeMixin and Neo4j::RelationshipMixin modules.
  • Layer 3. An implementation of the Rails Active Model and a subset of the Active Record API, see Neo4j::Rails::Model class.
  • In this blog I will only show the Neo4j::Rails::Model API.

    Installation

    Neo4j can be used as an embedded database. That means that it’s integrated in your application and does not
    need to be installed as a separate piece of software unlike e.g mysql. This may simplify installation and deployments.
    You can declare the database in your Gemfile and that is all you need to do get it installed.

    You also need to install Java and JRuby. If you got RVM installed you simply install JRuby with:

    rvm install jruby-1.6.0.RC2

    Here are some good links for installing Java and RVM on Ubuntu:
    How to install Sun JDK on Ubuntu 10.10 “Maverick meerkat”?,
    Installing Ruby on Ubuntu 10.10 with RVM

    Create a Rails 3 Project Template

    First make sure you have installed Rails 3.

    gem install rails

    Then you create a new Rails application using the neo4j.rb project template
    which will configure Rails to use Neo4j instead of ActiveRecord.

    rails new myblog -m http://andreasronge.github.com/rails3.rb

    Now, lets install all the dependencies including the Neo4j graph database, type:

    cd myblog
    bundle

    Create the first model

    To generate a model for Neo4j, controller and view, type:

    rails generate scaffold post title:string body:string

    Now, lets try this application by starting Rails

    rails s

    and open a webbrowser http://localhost:3000/posts

    Simliary, run this command to create scaffolds for comments

    rails generate scaffold comment name:string body:string

    Declare a Relationship

    You now have two models that needs a relationship between them.
    Declare a has_n comment relationship accessor method in the app/models/post.rb file

    Edit the comment.rb file

    Neo4j is a schema free database, that means that you can add relationships and properties at any time you like. Since the data for a blog application is rather well structured (we know that each post has a title and body and a number of comments) we choose to declare it.
    Also, by using the property and has_n methods neo4j.rb will generate some convinience methods for manipulation of properties and relationships.

    Rails Console, example

    The rails console is a very handy tool to test the generated has_n and property methods, example:

    > p = Post.create :title => 'first blog', :body => 'bla bla bla'
    Enable remote shell at port port=9332
    Starting local Neo4j using db /home/andreas/projects/myblog/db/neo4j-development
    => # p.title
    => "first blog"
    > p[:title] => "first blog"
    > p.title = 'my first blog'
    => "my first blog"
    > p.title
    => "my first blog"
    > p.save

    Notice that you need to call save in order to save the update property to the database, just like ActiveRecord.
    Now lets create two comments and a relationship between the post and comments.


    > p.comments << Comment.create(:name => 'wrong wrong') << Comment.create(:name => 'comment 2')
    > p.save
    > p.comments.collect{|x| x.name}
    => ["wrong wrong", "comment 2"]

    The generated method ‘comments’ is both used to create new relationships and for traversing all outgoing relationship of type comments of depth 1. It returns an object that includes the standard Ruby Enumerable mixin (where e.g. the collect method is defined).

    Notice that there was no need to use migrations. Migrations is only needed when you have a database in production and need to change the structure or index of the data.

    Allow User to Comment

    We need to edit the routes to get nested URLs for post and comment.
    Edit first part of the config/routes.rb file

    Remove the default index page

    rm public/index.html

    Now modify the app/views/posts/show.html.erb file to be the same as the code below. Here, we are rendering the post, showing any related comments and then displaying a form to add new comments.

    Title:
    <%= @post.title %>

    Body:
    <%= @post.body %>

    <h2>Comments</h2>

    <% @post.comments.each do |c| %>

    <%= c.name %> said:
    <%= time_ago_in_words(c.created_at) %>

    <%= c.body %>

    <% end %>

    <% form_for [@post, Comment.new] do |f| %>

    <%= f.label :name, "Author" %>
    <%= f.text_field :name %>
    <%= f.label :body, "Comment Description" %>
    <%= f.text_area :body %>

    <%= f.submit "Add Comment" %>

    <% end %>

    Modify the Comments Controller

    Remove all the methods that were automatically created in the comments_controller.rb file, as they are not required for our web app. Add one new method called “create” as shown in the code below.
    This method simply creates a comment node and connect it to the given post with the relationship of type ‘comments’

    And start the server and open the web browser.
    You will now see something like this:

    More ?

    There is a lot more to be discovered like – the ActiveModel validations, callbacks, xml serializer
    , devise, will_paginate, ActiveRecord accept_nested_attributes_for and the Lucene query language, traversal, graph algorithms, see the Neo4j/Rails Guide.

    11 Comments

    1. Jay

      It would be appreciated if a video tutorial of real time usage of neo4j with ruby on rails is made available. This can be even sold since i know many of new developers looking to use neo4j are stuck as i am.
      thanks J

    2. Jay

      It would be appreciated if a video tutorial of real time usage of neo4j with ruby on rails is made available. This can be even sold since i know many of new developers looking to use neo4j are stuck as i am.

    3. I agree.
      A Blog is not a very realistic usage for a graph engine. For a blog I would still choose a relational DBMS or a Document DB like MongoDB.
      A typical Usage for Graph Engines are social networks. Modeling the relationships between people.
      But anyway. This is a good blog post. Thank you very much for that.

    4. Is there a convenient way of importing an owl file into a rails app that is using neo4j.rb?

    5. Raghavan

      I have followed this blog to setup a rails application with Neo4j.

      I have my rvm setup and installed JRuby-1.6.0.RC2 and rails3. When I do bundle install, I get the following error

      Java::JavaLang::ArrayIndexOutOfBoundsException: An error occured while installing multi_json (1.1.0), and Bundler cannot continue.
      Make sure that gem install multi_json -v '1.1.0' succeeds before bundling.

      when I try to do “gem install multi_json -v ‘1.1.0’, I get another error

      gem install multi_json -v ‘1.1.0’
      ERROR: While executing gem … (ConcurrencyError)
      Detected invalid array contents due to unsynchronized modifications with concurrent users

      My .rvmrc file looks like this

      rvm use jruby-1.6.0.RC2@project

      I tried to install the example kvitter application and the exact same errors show up there as well.

      Any pointers to resolve this and install the application will be very much appreciated.

    6. Raghavan

      Update:

      I found fix myself.

      The problem was with JRuby-1.6.0-RC2. I tried the install with JRuby-1.6.5 and everything went on smoothly.

      Hope this will be helpful to someone.

    7. Justyna

      Hello!
      I am trying to create my first application with use of Ruby on Rails (3) and Neo4j.
      I have a problem with a person:) I have created Person model class and People Controller (with use of Scaffolding). I can create nodes of Person (I can see it in Neoclipse), but when I try to find a person with given name, RoR gives me the answer, that there is no such a person.
      I have tested it with other classes, like place, device etc. and it works perfectly.
      May it be a problem with different pluralization of a word “person”? Do you know how to fix this problem?

    8. darek

      Would be cool to see Neo4j on rails with tree structure especially some bigger one :)

    Trackbacks for this post

    1. Neo4j.rb – A Graph Database for JRuby - TurboLinux Blog
    2. Neo4j.rb 2.0 – An Overview | Jayway Team Blog - Sharing Experience
    3. ruby gem error: “ERROR: While executing gem … (ConcurrencyError)” | Kev's Development Toolbox

    Leave a Reply