Ooor
Odoo Ruby JSON client. Emulates ActiveRecord enough (as much as Mongoid; Implements ActiveModel) to make Rails development with an Odoo datastore straightforward
Install / Use
/learn @akretion/OoorREADME
Why use Ooor?
- Ooor is an administration Swiss Army knife in an interactive Ruby session. You connect remotely to any running Odoo instance without stopping it, without compromising its security. It has tab auto-completion and object introspection features. You can script anything you would do in the web interface or in an Odoo module with the same level of query optimization.
- Ooor is the basis for unleashed web development. It is Rack based and inject proxies to Odoo entities in your Rack env just like you use them in your env registry in Odoo modules. You use it in popular Ruby web frameworks such as Sinatra or Rails.
Odoo is all the rage for efficiently building an ERP back-office, but sometimes you want freedom and scalablity for your web front ends. Ooor enables you to model your web app using standard web frameworks like Rails while using Odoo as the persistence layer - without data duplication or synchronization/mapping logic - and reusing the Odoo business logic. Ooor even has an optionnal Rack filter that enables you to proxy some Odoo applications of your choice (say the shopping cart for instance) and share the HTTP session with it.
Because Ooor is ActiveModel based and emulates the ActiveRecord API well enough, it just works with popular Ruby gems such as Devise for authentication, will_paginate for pagination, SimpleForm, Cocoon for nested forms...
Ooor is also a lot more advanced than its Python clones: it is very carefuly designed to save Odoo requests. It can avoid the N+1 queries and also works smartly with the Rails cache so that the meta-data used to define the Odoo proxies can be cached shared between concurrent Rails workers without the need to hit Odoo again with requests such as fields_get.
Related projects - a full web stack!
- Ooorest, Ooor is the Model layer of MVC. Ooorest is the Controller layer, enforcing a clean Railish REST API and offering handy helper to use Odoo in your Rails application.
- Aktooor, Aktooor is the missing View layer of MVC. It's based on SimpleForm, that is a clean minimalist framework that extend Rails form framework over Twitter Bootstrap
- Erpify, Erpify is Odoo inside the Liquid non evaling language, that is the templating language of Shopify or LocomotiveCMS for instance.
- Locomotive-erpify, Erpify for LocomotiveCMS, both the engine and the Wagon local editor
- Solarize, pulling data from Odoo relational database may not scale to your need. No problem with Solarize: you can index your OpenERP data with the Solerp OpenERP module, then search it using SolR API and even load it from SolR without even hitting OpenERP!
- TerminatOOOR, a Pentaho ETL Kettle plugin allowing to push/pull data into/from Odoo with an incomparable flexibility and yet benefit all standard ETL features, including the AgileBI OLAP business intelligence plugin.
How?
Odoo is a Python based open source ERP. But every Odoo business method is actually exposed as a JSON-RPC webservice (SOA orientation, close to being RESTful). Ooor doesn't connect to the Odoo database directly, Instead it uses the Odoo JSON-RPC API so it fully enforces Odoo security model and business logic.
Ooor is around 2000 lines of code and has a test coverage over 93%. The API it exposes is not invented but it is the one of Rails: it is modeled after Rails ActiveModel, ActiveResource and ActiveRecord layers.
More specifically, an Odoo Ooor proxy implements the ActiveModel API. Instead of depending on ActiveResource which is actually a bit different (not multi-tenant, little access right management), we copied a tiny subset of it in the mini_active_resource.rb file and Odoo proxies include this module. Finally Ooor emulates the ActiveRecord API wherever possible delegating its requests to Odoo using Odoo domain S expressions instead of SQL. The ActiveRecord API emulation is actually pretty good: think Ooor looks more like ActiveRecord than Mongoid; it has associations, surface ARel API, Reflection API, can be paginated via Kaminary, can be integrated with SimpleForm or Cocoon seamlessly...
Ooor features several session modes: in the default IRB console usage it uses a global login scheme and generate constants for your OpenERP proxies, such as ProductProduct for the product.product OpenERP object much like Rails ActiveRecord. In web mode instead, you can have several sessions and do session['product.product'] to get a proxy to the Product object matching your current session credentials, chosen database and OpenERP url (yes Ooor is not only multi-database like OpenEP, it's in fact multi-OpenERP!)
Installation
$ gem install ooor
Warning Ooor has been ureleased for several months, don't hesitate to run the git version instead
Trying it simply
Once you installed the OOOR gem, you get a new OOOR command line. Basic usage is:
$ ooor username:password@host:port/database
This will bring you in a standard IRB interpreter with an ooor client already connected to your Odoo server so you can start playing with it.
Standalone (J)Ruby application:
Let's test ooor in an irb console (irb command):
require 'rubygems'
require 'ooor'
Ooor.new(:url => 'http://localhost:8069/xmlrpc', :database => 'mybase', :username => 'admin', :password => 'admin')
This should load all your Odoo models into Ruby proxy Activeresource objects. Of course there are option to load only some models. Let's try to retrieve the user with id 1:
ResUsers.find(1)
(in case you have an error like "no such file to load -- net/https", then on Debian/Ubuntu, you might need to do before: apt-get install libopenssl-ruby)
(J)Ruby on Rails application:
Please read details https://github.com/rvalyi/ooor/wiki/(J)Ruby-on-Rails-application
API usage
Note: Ruby proxy objects are named after Odoo models in but removing the '.' and using CamelCase. (we remind you that Odoo tables are also named after Odoo models but replacing the '.' by '_'.)
Basic finders:
ProductProduct.find(1)
ProductProduct.find([1,2])
ProductProduct.find([1])
ProductProduct.find(:all)
ProductProduct.find(:last)
Odoo domain support (same as Odoo):
ResPartner.find(:all, :domain=>[['supplier', '=', 1],['active','=',1]])
#More subtle now, remember Odoo use a kind of inverse polish notation for complex domains,
#here we look for a product in category 1 AND which name is either 'PC1' OR 'PC2':
ProductProduct.find(:all, :domain=>[['categ_id','=',1],'|',['name', '=', 'PC1'],['name','=','PC2']])
Odoo context support (same as Odoo):
ProductProduct.find(1, :context => {:my_key => 'value'})
Request params or ActiveResource equivalence of Odoo domain (but degraded as only the = operator is supported, else use domain):
ResPartner.find(:all, :params => {:supplier => true})
Odoo search method:
ResPartner.search([['name', 'ilike', 'a']], 0, 2)
Arguments are: domain, offset=0, limit=false, order=false, context={}, count=false
Relations (many2one, one2many, many2many) support:
SaleOrder.find(1).order_line #one2many relation
p = ProductProduct.find(1)
p.product_tmpl_id #many2one relation
p.taxes_id #automagically reads man2many relation inherited via the product_tmpl_id inheritance relation
p.taxes_id = [1,2] #save a many2many relation, notice how we bypass the awkward Odoo syntax for many2many (would require [6,0, [1,2]]) ,
p.save #assigns taxes with id 1 and 2 as sale taxes,
see [the official Odoo documentation](http://doc.openerp.com/developer/5_18_upgrading_server/19_1_upgrading_server.html?highlight=many2many)```
Inherited relations support:
```ruby
ProductProduct.find(1).categ_id #where categ_id is inherited from the ProductTemplate
Please notice that loaded relations are cached (to avoid hitting Odoo over and over) until the root object is reloaded (after save/update for instance).
Load only specific fields support (faster than loading all fields):
ProductProduct.find(1, :fields=>["state", "id"])
ProductProduct.find(:all, :fields=>["state", "id"])
ProductProduct.find([1,2], :fields=>["state", "id"])
ProductProduct.find(:all, :fields=>["state", "id"])
even in relations:
SaleOrder.find(1).order_line(:fields => ["state"])
Create:
pc = ProductCategory.new(:name => 'Categ From Rails!')
# <ProductCategory:0xb702c42c @prefix_options={}, @attributes={"name"=>"Categ From Rails!"}>
pc.create
pc.id
# $ => 14
Update:
pc.name = "A new name"
pc.save
Copy:
copied_object = pc.copy({:categ_id => 2}) #first optionn
Related Skills
node-connect
345.4kDiagnose OpenClaw node connection and pairing failures for Android, iOS, and macOS companion apps
frontend-design
104.6kCreate distinctive, production-grade frontend interfaces with high design quality. Use this skill when the user asks to build web components, pages, or applications. Generates creative, polished code that avoids generic AI aesthetics.
openai-whisper-api
345.4kTranscribe audio via OpenAI Audio Transcriptions API (Whisper).
qqbot-media
345.4kQQBot 富媒体收发能力。使用 <qqmedia> 标签,系统根据文件扩展名自动识别类型(图片/语音/视频/文件)。






