Project

riagent

0.0
No commit activity in last 3 years
No release in over 3 years
Provides Ruby on Rails integration for the Riak KV NoSQL database (plus Solr search)
2005
2006
2007
2008
2009
2010
2011
2012
2013
2014
2015
2016
2017
2018
2019
2020
2021
2022
2023
2024
 Dependencies

Development

Runtime

 Project Readme

riagent

Object Document Mapper for Riak (including integration with Solr search), for use with Ruby on Rails 4 and Sinatra.

Requirements

  • Ruby 2+
  • Riak version 2.0 or later

Motivation

a.k.a. Why not just use a plain riak-ruby-client?

A Riak client just answers the question "How do I store stuff in Riak?". In order to develop any non-toy application using Riak as a persistence layer, a developer must answer further questions:

  • How do I define my model objects, and how do I serialize them so I can store them in Riak?
  • What will my access patterns be? Plain Key/Value reads and writes, or will I need to perform queries?
  • How do I integrate painlessly with my framework of choice? (Ruby on Rails, Sinatra)

Riagent attempts to provide answers to those questions, to encode recommended best-practice Riak query patterns, and in general to aid rapid application development by working with Riak's strengths while respecting its limitations. It is intended as a spiritual successor to Ripple.

Model Definition and Serialization

Riagent provides a model definition language that will be familiar to most Rails developers, via the riagent-document gem.

include 'riagent-document'

class User
  include Riagent::ActiveDocument

  attribute :username, String
  attribute :email, String
  attribute :country, String, default: 'USA'
end

Riagent::ActiveDocument instances provide a rich set of functionality including attribute defaults, type coercions, conversion to and from JSON, search schema creation, easy persistence to Riak, document embedding, and more. See the riagent-document README for more details.

Advanced Riak K/V and Query Support

Reads and writes of single objects into Riak are easy (and have the benefit of being massively scalable, highly concurrent, and fault-tolerant). But what about listing and querying? Every developer that gets past a Hello World get/put tutorial on Riak is soon faced with questions about more advanced access patterns. How do I implement collections, and list things? How do I search or query on various attributes? Should I use Secondary Indexes? What about Search/Solr integration?

Riagent provides a set of high-level notations and functionality that allows developers create collections and associations on Riak, either via plain K/V operations when possible, or via advanced mechanisms such as Solr queries when necessary.

class User
  include Riagent::ActiveDocument

  collection_type :riak_kv, list_keys_using: :riak_dt_set

  attribute :username, String
  attribute :email, String
  attribute :language, String, default: 'en'

  # Associations
  has_one :email_preference, :class => EmailPreference
  has_many :posts, :class => BlogPost, :using => :key_set

  # Validations
  validates_presence_of :username
end

Rails and Sinatra integration

Riagent and ActiveDocuments are integrated into the usual Rails workflow.

  • Riagent provides client configuration and initialization, via the config/riak.yml file
  • Provides a simple Key/Value persistence layer with save(), find(), update() and destroy() methods.
  • ActiveDocument implements the ActiveModel API. (Specifically, passes the ActiveModel Lint Test suite)
  • Provides a full range of validations for each attribute.
  • Provides before_save / after_save type Callback functionality
  • Provides a custom Query capability (to Riak/Solr), for searches, range queries, aggregations and more

Usage

Adding Riagent to a Rails App

Add it to the Gemfile of your Rails app:

gem 'riagent'

Run the install generator:

rails generate riagent:install

This creates a config/riak.yml file. Edit it to point to your running Riak instance.

Controller and View helpers

Since they implement the ActiveModel API, when you use ActiveDocuments in a Rails model, the usual link_to/route-based helpers work:

# In a user view file
<%= link_to @user.username, @user %> # => <a href="/users/EmuVX4kFHxxvlUVJj5TmPGgGPjP">HieronymusBosch</a>
<%= link_to 'Edit', edit_user_path(@user) %>  # => <a href="/users/EmuVX4kFHxxvlUVJj5TmPGgGPjP/edit">Edit</a>
# In a controller
redirect_to users_url

Validations

ActiveDocument supports the full range of ActiveModel validations

# Try saving an invalid document
new_user = User.new
new_user.valid?  # => false
puts user.errors.messages  # => {:username=>["can't be blank"]}
new_user.save  # => false (does not actually save, since document not valid)
new_user.save!  # => raises Riagent::InvalidDocumentError exception

# Now make it valid
new_user.username = 'HieronymusBosch'
new_user.valid?  # => true
new_user.save  # => saves and loads the generated key into document
new_user.key  # => 'EmuVX4kFHxxvlUVJj5TmPGgGPjP'

Key/Value Persistence

The usual array of CRUD type k/v operations is available to an ActiveDocument model.

Create documents via save() and save!()

user = User.new({username: 'John', email: 'john@doe.com'})
# If you save without specifying a key, it generates a UUID key automatically
user.save  # => 'EmuVX4kFHxxvlUVJj5TmPGgGPjP'

To load a document by key, use find():

user = User.find('EmuVX4kFHxxvlUVJj5TmPGgGPjP')

Update and Delete work in a similar fashion

user.username = 'New Name'
user.update  # update!() is also available
user.destroy  # deletes the document

Callbacks

ActiveDocument currently supports before_* and after_* callbacks for the following events: [:create, :update, :save, :destroy]

Testing the Riagent gem

First, set up the Riak config file for (and make sure it's pointing to a running Riak instance)

cp test/config/riak.yml.example test/config/riak.yml

The integration tests require that a Set bucket type be created, named sets:

riak-admin bucket-type create sets '{"props":{"datatype":"set"}}'
riak-admin bucket-type activate sets

To run the tests:

bundle exec rake test