0
* #sor09
Ruby sittin’ on the Couch
About me


• Alexander Lang
• Upstream Agile GmbH, Berlin
  programmer, owner
• http://upstream-berlin.com
11/52
Web development w/
      Ruby
BDD
Buzzword Driven
 Development
TDD
  BDD
                                   “agile”
Pair Programming


          * all the f****** time
About me

• playing with CouchDB since 09/2008
• helped hack the CouchDB statistics module
  (with @janl)
• wrote Couch Po...
Who are you?
Who is in this room?
• Chris Anderson
• George Palmer
• Paul Carey
• Johan Sørensen
• Cheah Chu Yeow/Carlos Villela
Who is in this room?
• Chris Anderson (couchrest + couchapp)
• George Palmer (couch_foo)
• Paul Carey (relaxdb)
• Johan Sø...
Forget it!
Agenda

• CouchDB introduction
• The CouchDB example wiki
• The frameworks
• Conclusion: where to go from here?
• Q &A
CouchDB introduction
What is CouchDB?
Apache Project
   so it has to be good
Document oriented
    Database
Store/read any JSON
     document
Powerful map/reduce
 views for querying*
     * we’ll see what that is
Why CouchDB?
Buzzword
compliant
JavaScript
REST
HTTP interface
JSON
Map/Reduce
the thing that made Google rich
Fun !
No more SQL/Schema/
    Migrations
JavaScript views instead
Simple!
HTTP interface
can use existing
clients, libraries
It scales
just like Ruby :)
No locks,
instead MVCC
integrated replication
      (yes, multi master)
use existing load
balancer, proxies etc.
        HTTP ftw
and so on...
So how does Couch work?
JSON
{
    _id: “some UUID”,
    _rev: “MVCC key”,
    title: “page one”
    body: “this is page one.”,
    tags: [“ruby”,...
HTTP API

• POST ‘/my_db’, {my_json}
• GET ‘/my_db/my_document_id’
• PUT ‘/my_db/my_document_id’,
  {new_json}
• DELETE ‘/...
Map/Reduce views

• views are documens
• provide a map (and optional reduce
  function) written in JavaScript
• this creat...
Map/Reduce views
{
    title: “page one”,
    tags: [“first”, important”]
}

{
    title: “page 2”,
    tags: [“funny”]
}
Map/Reduce views
{                                function(doc) {
    title: “page one”,
                                 ...
Map/Reduce views
{                                function(doc) {
    title: “page one”,
                                 ...
Map/Reduce views
{                                function(doc) {
    title: “page one”,
                                 ...
Map/Reduce views
{                                function(doc) {
    title: “page one”,
                                 ...
Query a View
Query a View

/my_db/_design/wiki/_view/tags_count
Query a View

/my_db/_design/wiki/_view/tags_count
/my_db/_design/wiki/_view/tags_count?reduce=false
Query a View

/my_db/_design/wiki/_view/tags_count
/my_db/_design/wiki/_view/tags_count?reduce=false
/my_db/_design/wiki/_...
Query a View

/my_db/_design/wiki/_view/tags_count
/my_db/_design/wiki/_view/tags_count?reduce=false
/my_db/_design/wiki/_...
Query a View

/my_db/_design/wiki/_view/tags_count
/my_db/_design/wiki/_view/tags_count?reduce=false
/my_db/_design/wiki/_...
Query a View
Query a View
  ?key=‘page one’
Query a View
          ?key=‘page one’
?startkey=‘page 1’&endkey=’page 999’
Query a View
          ?key=‘page one’
?startkey=‘page 1’&endkey=’page 999’
      ?key=[‘composite’, ‘key’]
Query a View
           ?key=‘page one’
?startkey=‘page 1’&endkey=’page 999’
      ?key=[‘composite’, ‘key’]
       ?keys=...
Query a View
           ?key=‘page one’
?startkey=‘page 1’&endkey=’page 999’
      ?key=[‘composite’, ‘key’]
       ?keys=...
That is CouchDB
                 (the basics)


• upload documents via POST/PUT
• read documents via GET
• create indexes ...
The CouchDB example wiki
Example Wiki
• ActiveRecord   • RelaxDB
• CouchRest      • Couch Potato
• ActiveCouch    • CouchOject
• CouchFoo       • C...
• a wiki example app implemented in all
      frameworks I could find
   • + in ActiveRecord for comparison

DISCLAIMER: im...
http://github.com/langalex/couchdb_example_wiki
Example Wiki

• a few simple features
 • create a page
 • add new pages by clicking on a
    CamelCase link
 • list of pag...
Example Wiki

• and a few special cases
 • keep history of each page, browse old
    versions
 • statistics: count occurre...
Example Wiki

• creating pages is easy
• versioning, statistics harder
• views are the source of CouchDB’s power
let me show you how it works
          Example Wiki
ActiveRecord Wiki
routes.rb
map.resources :pages do |pages|
  pages.resources :versions
end

map.resources :statistics
map.root :controller ...
page.rb
class Page < ActiveRecord::Base
  acts_as_versioned

  def to_param
    title
  end
end
pages/show.html.erb
<%= <%= simple_format linkify(@page.body) %>
    simple_format linkify(@page.body) %>



  def linkify...
pages_controller.rb

def show
  @page = Page.first unless params[:id]
  @page ||= Page.find_by_title params[:id]
  redirec...
statistics
  def self.word_counts
    Page.all.map(&:body).join(quot; quot;).split(/s
+/).grep(/w+/i).inject(Hash.new(0)) ...
schema.rb
create_table   quot;page_versionsquot;, :force => true do |t|
  t.integer    quot;page_idquot;
  t.integer    qu...
AR Summary

• Page has_many PageVersions
• ugly schema with duplicated table
• acts_as_versioned does the magic for us
• s...
CouchDB Wiki
  How does it work?
The Page
{
    _id: “89765”,
    _rev: “lb7tlb”,
    type: “Page”,
    title: “page one”,
    body: “this is page one”
}
Page Versions
{
    _id: “765”,
    _rev: “lhjb97”
    type: “PageVersion”,
    title: “page one”,
    body: “this is page...
All in one namespace
    {                                                                            {
        _id: “ 897...
Finding pages
function(doc) {                 key       value
  if(doc.type == “Page”) {
    emit(doc.title, doc);
       ...
Finding Page Versions
function(doc) {
  if(doc.type == “PageVersion”) {
    emit([doc.page_id, doc.version], doc);
  }
}  ...
Finding Page Versions
                               key          value
                          [“ladsb7gi”, 1]   {...}
...
Counting Words - Map
Counting Words - Map



{body: “page one”}
 {body: “page 2”}
Counting Words - Map
function(doc) {
  if(doc.type == 'Page') {
    var words = doc.body.split(/W/);
    words.forEach(fun...
Counting Words - Map
function(doc) {
  if(doc.type == 'Page') {
    var words = doc.body.split(/W/);
    words.forEach(fun...
Counting Words - reduce
Counting Words - reduce
 key     value
“page”     1
“page”     1
“one”      1
 “2”       1
Counting Words - reduce
  key          value
 “page”          1
 “page”          1
 “one”           1
  “2”            1

...
Counting Words - reduce
  key          value
 “page”          1
 “page”          1
 “one”           1
  “2”            1
 ...
CouchDB summary

• no schema, arbitrary documents in one
  namespace
• still use foreign keys to implement
  associations
...
Show us the
frameworks already
What’s the framework’s job?
What’s the framework’s job?
      ActiveRecord
What’s the framework’s job?
         ActiveRecord

• map objects to relations and back
• do the whole SQL thing
What’s the framework’s job?
              ActiveRecord
schema                                   attribute auto
tracking   ...
What’s the framework’s job?
          ActiveRecord
           Page.all :include => :tags



SELECT pages.id ... JOIN tags ...
What’s the framework’s job?
      ActiveRecord

      big fat abstraction


            SQL
What’s the framework’s job?
 ActiveCouchRelaxFooDBObject
What’s the framework’s job?
 ActiveCouchRelaxFooDBObject

      <#134 Page title=”page one”>




{type: “Page”, title: “pa...
What’s the framework’s job?
 ActiveCouchRelaxFooDBObject


POST /mydb/, {title: “page one”, type: “Page”}

            GET...
What’s the framework’s job?
 ActiveCouchRelaxFooDBObject


                          skinny
         CouchDB        abstra...
ActiveCouchRelaxFooDBObject


          ... are not *that* important
The frameworks

       CouchPoato        RelaxDB
                    CouchObject
ActiveCouch
                        Couch...
CouchRest


• 2 in 1
• foundation for most
  other frameworks
Low level part

• relatively thin layer on top of RestClient
• store and retrieve JSON structures
• query views the Couch ...
Class mapping part


• map Ruby classes to JSON documents
• CRUD
• declarative views with CouchDB
  semantics
RelaxDB

• CRUD + very basic associations
• automatic view generation via view_by
• a bit of support for custom views via
...
Couch Object

• last updated in 2007
• pretty low level - okay for learning
  the details of Couch the DIY way
• no update...
Couch Potato
• CRUD, associations + JSON mapping
• built-in acts_as_versioned - 60 LOC but
  doing it by hand only require...
CouchFoo

• takes ActiveRecord and makes it
  work with CouchDB
• if you (have) to migrate an AR
  app...
• doesn’t give y...
ActiveCouch
• “Object Relational Mapper for [..]
  CouchDB”
• “Since, the Rubyists here at Wego are
  already very familia...
ActiveCouch

• one database per model
• View class to upload #@!? views via Rake
  task
• no support for custom views
Use the source
CouchRest Wiki
Page CRUD
class Page < CouchRest::ExtendedDocument
  update_callback :after, :create_version

  property :title          c...
PageVersion

class PageVersion < CouchRest::ExtendedDocument
  property :body
  property :version
  property :page_id

  v...
Word Count
class WordCount < CouchRest::ExtendedDocument
  view_by :all, :map => quot;function(doc) {
     if(doc['couchre...
Querying Views
Page.by_title

Page.by_created_at(:limit => 1)

PageVersion.get params[:id]

Page.by_title(:key => title, :...
One more thing
CouchApp


• serve entire apps directly from CouchDB
• just JSON, HTML & JavaScript
What is CouchApp

• bunch of Ruby Python scripts to help with
  development/deployment
• data, CouchDB views, validations,...
AJAX apps
•   serve HTML, CSS as assets

•   do all the work in JavaScript

•   in the browser: GET from couch and append
...
“real” apps

• lists
• shows
• server HTML, XML etc. from CouchDB
Conclusion
DON’T

use ActiveCouch
unless you understand why it is
the way it is

or Couch Potato
I’ll break all of its bones and APIS
DON’T


or CouchFoo
unless you want more power
than AR can give you
Conclusion


forgetting about the ActiveRecord way
is more important than what framework
Conclusion


think in documents & views,
not in records and associations
Conclusion


CouchDB is not about finding your
records, it’s about clever map/reduce
to get exactly what you want
What you want is


a thin abstraction
CouchDB semantics, not ActiveRecord
start simple with CouchREST or RelaxDB
and relax...




       time to relax
Resources
•   The CouchDB book
    http://books.couchdb.org/relax/

•   jchris CouchApp talk
    http://jchrisa.net/drl/Co...
Questions?
• Email: alex@upstream-berlin.com
• Twitter: @langalex




                   time to relax
Ruby sittin' on the Couch
Upcoming SlideShare
Loading in...5
×

Ruby sittin' on the Couch

6,086

Published on

The talk gives an introduction to CouchDB by showing the implementing of a simple Wiki Rails application that I have implemented in all the available Ruby frameworks I could find. It then compares these frameworks and suggests which to use in order to get started with CouchDB and Ruby.

Published in: Technology
0 Comments
11 Likes
Statistics
Notes
  • Be the first to comment

No Downloads
Views
Total Views
6,086
On Slideshare
0
From Embeds
0
Number of Embeds
2
Actions
Shares
0
Downloads
112
Comments
0
Likes
11
Embeds 0
No embeds

No notes for slide

Transcript of "Ruby sittin' on the Couch"

  1. 1. * #sor09
  2. 2. Ruby sittin’ on the Couch
  3. 3. About me • Alexander Lang • Upstream Agile GmbH, Berlin programmer, owner • http://upstream-berlin.com
  4. 4. 11/52
  5. 5. Web development w/ Ruby
  6. 6. BDD
  7. 7. Buzzword Driven Development
  8. 8. TDD BDD “agile” Pair Programming * all the f****** time
  9. 9. About me • playing with CouchDB since 09/2008 • helped hack the CouchDB statistics module (with @janl) • wrote Couch Potato • working on smaller production apps
  10. 10. Who are you?
  11. 11. Who is in this room? • Chris Anderson • George Palmer • Paul Carey • Johan Sørensen • Cheah Chu Yeow/Carlos Villela
  12. 12. Who is in this room? • Chris Anderson (couchrest + couchapp) • George Palmer (couch_foo) • Paul Carey (relaxdb) • Johan Sørensen (couchbject) • Cheah Chu Yeow/Carlos Villela (activecouch)
  13. 13. Forget it!
  14. 14. Agenda • CouchDB introduction • The CouchDB example wiki • The frameworks • Conclusion: where to go from here? • Q &A
  15. 15. CouchDB introduction
  16. 16. What is CouchDB?
  17. 17. Apache Project so it has to be good
  18. 18. Document oriented Database
  19. 19. Store/read any JSON document
  20. 20. Powerful map/reduce views for querying* * we’ll see what that is
  21. 21. Why CouchDB?
  22. 22. Buzzword compliant
  23. 23. JavaScript
  24. 24. REST HTTP interface
  25. 25. JSON
  26. 26. Map/Reduce the thing that made Google rich
  27. 27. Fun !
  28. 28. No more SQL/Schema/ Migrations
  29. 29. JavaScript views instead
  30. 30. Simple!
  31. 31. HTTP interface
  32. 32. can use existing clients, libraries
  33. 33. It scales
  34. 34. just like Ruby :)
  35. 35. No locks, instead MVCC
  36. 36. integrated replication (yes, multi master)
  37. 37. use existing load balancer, proxies etc. HTTP ftw
  38. 38. and so on...
  39. 39. So how does Couch work?
  40. 40. JSON { _id: “some UUID”, _rev: “MVCC key”, title: “page one” body: “this is page one.”, tags: [“ruby”, “couchdb”, “sor09”] metadata: {created_at: “2009/03/28 06:34:00”, author: “alex”} }
  41. 41. HTTP API • POST ‘/my_db’, {my_json} • GET ‘/my_db/my_document_id’ • PUT ‘/my_db/my_document_id’, {new_json} • DELETE ‘/my_db/my_document_id’
  42. 42. Map/Reduce views • views are documens • provide a map (and optional reduce function) written in JavaScript • this creates an index over all documents • query that index via GET
  43. 43. Map/Reduce views { title: “page one”, tags: [“first”, important”] } { title: “page 2”, tags: [“funny”] }
  44. 44. Map/Reduce views { function(doc) { title: “page one”, emit(doc.title, doc.tags.length) tags: [“first”, important”] } } { title: “page 2”, tags: [“funny”] }
  45. 45. Map/Reduce views { function(doc) { title: “page one”, emit(doc.title, doc.tags.length) tags: [“first”, important”] } } key value { “page one” 2 title: “page 2”, tags: [“funny”] “page 2” 1 }
  46. 46. Map/Reduce views { function(doc) { title: “page one”, emit(doc.title, doc.tags.length) tags: [“first”, important”] } } key value { “page one” 2 title: “page 2”, tags: [“funny”] “page 2” 1 } function(keys, values) { return sum(values); }
  47. 47. Map/Reduce views { function(doc) { title: “page one”, emit(doc.title, doc.tags.length) tags: [“first”, important”] } } key value { “page one” 2 title: “page 2”, tags: [“funny”] “page 2” 1 } function(keys, values) { return sum(values); 3 }
  48. 48. Query a View
  49. 49. Query a View /my_db/_design/wiki/_view/tags_count
  50. 50. Query a View /my_db/_design/wiki/_view/tags_count /my_db/_design/wiki/_view/tags_count?reduce=false
  51. 51. Query a View /my_db/_design/wiki/_view/tags_count /my_db/_design/wiki/_view/tags_count?reduce=false /my_db/_design/wiki/_view/tags_count?limit=1
  52. 52. Query a View /my_db/_design/wiki/_view/tags_count /my_db/_design/wiki/_view/tags_count?reduce=false /my_db/_design/wiki/_view/tags_count?limit=1 /my_db/_design/wiki/_view/tags_count?key=page one
  53. 53. Query a View /my_db/_design/wiki/_view/tags_count /my_db/_design/wiki/_view/tags_count?reduce=false /my_db/_design/wiki/_view/tags_count?limit=1 /my_db/_design/wiki/_view/tags_count?key=page one
  54. 54. Query a View
  55. 55. Query a View ?key=‘page one’
  56. 56. Query a View ?key=‘page one’ ?startkey=‘page 1’&endkey=’page 999’
  57. 57. Query a View ?key=‘page one’ ?startkey=‘page 1’&endkey=’page 999’ ?key=[‘composite’, ‘key’]
  58. 58. Query a View ?key=‘page one’ ?startkey=‘page 1’&endkey=’page 999’ ?key=[‘composite’, ‘key’] ?keys=[‘set’, ‘of’, ‘keys’]
  59. 59. Query a View ?key=‘page one’ ?startkey=‘page 1’&endkey=’page 999’ ?key=[‘composite’, ‘key’] ?keys=[‘set’, ‘of’, ‘keys’]
  60. 60. That is CouchDB (the basics) • upload documents via POST/PUT • read documents via GET • create indexes by providing map/reduce functions • query views via GET, pass keys + other options
  61. 61. The CouchDB example wiki
  62. 62. Example Wiki • ActiveRecord • RelaxDB • CouchRest • Couch Potato • ActiveCouch • CouchOject • CouchFoo • CouchApp
  63. 63. • a wiki example app implemented in all frameworks I could find • + in ActiveRecord for comparison DISCLAIMER: implementations are insecure, have bugs and aren’t meant for production at all
  64. 64. http://github.com/langalex/couchdb_example_wiki
  65. 65. Example Wiki • a few simple features • create a page • add new pages by clicking on a CamelCase link • list of pages
  66. 66. Example Wiki • and a few special cases • keep history of each page, browse old versions • statistics: count occurrences of all words in all pages
  67. 67. Example Wiki • creating pages is easy • versioning, statistics harder • views are the source of CouchDB’s power
  68. 68. let me show you how it works Example Wiki
  69. 69. ActiveRecord Wiki
  70. 70. routes.rb map.resources :pages do |pages| pages.resources :versions end map.resources :statistics map.root :controller => quot;pagesquot;, :action => 'show'
  71. 71. page.rb class Page < ActiveRecord::Base acts_as_versioned def to_param title end end
  72. 72. pages/show.html.erb <%= <%= simple_format linkify(@page.body) %> simple_format linkify(@page.body) %> def linkify(text) text.gsub(/([A-Z][a-z]+([A-Z][a-z]+)+)/) do link_to($1, page_path($1)) end end replace CamelCase words with links to #show
  73. 73. pages_controller.rb def show @page = Page.first unless params[:id] @page ||= Page.find_by_title params[:id] redirect_to new_page_path(:title => params[:id]) unless @page end redirect to #new if no page found
  74. 74. statistics def self.word_counts Page.all.map(&:body).join(quot; quot;).split(/s +/).grep(/w+/i).inject(Hash.new(0)) do |res, word| res[word] += 1 res end end
  75. 75. schema.rb create_table quot;page_versionsquot;, :force => true do |t| t.integer quot;page_idquot; t.integer quot;versionquot; t.text quot;bodyquot; t.datetime quot;created_atquot; t.datetime quot;updated_atquot; end create_table quot;pagesquot;, :force => true do |t| t.string quot;titlequot; t.text quot;bodyquot; t.datetime quot;created_atquot; t.datetime quot;updated_atquot; t.integer quot;versionquot;, :default => 1 end
  76. 76. AR Summary • Page has_many PageVersions • ugly schema with duplicated table • acts_as_versioned does the magic for us • statistics - ?!?
  77. 77. CouchDB Wiki How does it work?
  78. 78. The Page { _id: “89765”, _rev: “lb7tlb”, type: “Page”, title: “page one”, body: “this is page one” }
  79. 79. Page Versions { _id: “765”, _rev: “lhjb97” type: “PageVersion”, title: “page one”, body: “this is page one”, version: 23, page_id: “89765” }
  80. 80. All in one namespace { { _id: “ 89765”, { _id: “ 9753”, _id: “97865”, _rev: “lb7tlb”, _rev: “lb7tlb”, _rev: “lhjb97” type: “Page”, type: “PageVersion”, type: “Page”, title: “page one”, title: “page one”, title: “page one”, body: “this is page one”, body: “this is page one” version: 23, body: “this is page one” page_id: “89765” } { } } _id: “6437”, _rev: “lhjb97” { type: “PageVersion”, _id: “6367”, title: “page one”, { { _rev: “lhjb97” body: “this is page one”, type: “PageVersion”, _id: “ 76538”, _id: “ 8975763”, version: 23, title: “page one”, page_id: “89765” _rev: “lb7tlb”, } _rev: “lb7tlb”, body: “this is page one”, version: 23, type: “Page”, type: “Page”, page_id: “89765” title: “page one”, title: “page one”, } body: “this is page one” body: “this is page one” } }
  81. 81. Finding pages function(doc) { key value if(doc.type == “Page”) { emit(doc.title, doc); “page 2” {...} } } “page one” {...}
  82. 82. Finding Page Versions function(doc) { if(doc.type == “PageVersion”) { emit([doc.page_id, doc.version], doc); } } key value [“ladsb7gi”, 1] {...} [“ladsb7gi”, 2] {...} [“nloh79d”, 1] {...}
  83. 83. Finding Page Versions key value [“ladsb7gi”, 1] {...} [“ladsb7gi”, 2] {...} [“nloh79d”, 1] {...} GET /mydb/_design/page_versions/_view/by_page? startkey=[“ladsb7gi”, 1]&endkey=[“ ladsb7gi”,{}]
  84. 84. Counting Words - Map
  85. 85. Counting Words - Map {body: “page one”} {body: “page 2”}
  86. 86. Counting Words - Map function(doc) { if(doc.type == 'Page') { var words = doc.body.split(/W/); words.forEach(function(word) { if (word.length > 0) emit(word, 1); });}} {body: “page one”} {body: “page 2”}
  87. 87. Counting Words - Map function(doc) { if(doc.type == 'Page') { var words = doc.body.split(/W/); words.forEach(function(word) { if (word.length > 0) emit(word, 1); });}} key value “page” 1 {body: “page one”} “page” 1 {body: “page 2”} “one” 1 “2” 1
  88. 88. Counting Words - reduce
  89. 89. Counting Words - reduce key value “page” 1 “page” 1 “one” 1 “2” 1
  90. 90. Counting Words - reduce key value “page” 1 “page” 1 “one” 1 “2” 1 function(keys, values) { return sum(values); }
  91. 91. Counting Words - reduce key value “page” 1 “page” 1 “one” 1 “2” 1 key value “page” 2 function(keys, values) { return sum(values); “one” 1 } “2” 1
  92. 92. CouchDB summary • no schema, arbitrary documents in one namespace • still use foreign keys to implement associations • create views instead of join tables • views! views! views!
  93. 93. Show us the frameworks already
  94. 94. What’s the framework’s job?
  95. 95. What’s the framework’s job? ActiveRecord
  96. 96. What’s the framework’s job? ActiveRecord • map objects to relations and back • do the whole SQL thing
  97. 97. What’s the framework’s job? ActiveRecord schema attribute auto tracking detection serialized attributes pagination groups JOINS unique lazy loading caching • map objects to relations and back count • do the whole SQL thing HABTM create or update? has_many :through conditions eager association loading connection DDL :dependent => :destroy
  98. 98. What’s the framework’s job? ActiveRecord Page.all :include => :tags SELECT pages.id ... JOIN tags ON ... WHERE ... ... [10 more lines] ...
  99. 99. What’s the framework’s job? ActiveRecord big fat abstraction SQL
  100. 100. What’s the framework’s job? ActiveCouchRelaxFooDBObject
  101. 101. What’s the framework’s job? ActiveCouchRelaxFooDBObject <#134 Page title=”page one”> {type: “Page”, title: “page one”}
  102. 102. What’s the framework’s job? ActiveCouchRelaxFooDBObject POST /mydb/, {title: “page one”, type: “Page”} GET /mydb/page-one
  103. 103. What’s the framework’s job? ActiveCouchRelaxFooDBObject skinny CouchDB abstraction
  104. 104. ActiveCouchRelaxFooDBObject ... are not *that* important
  105. 105. The frameworks CouchPoato RelaxDB CouchObject ActiveCouch CouchRest CouchFoo
  106. 106. CouchRest • 2 in 1 • foundation for most other frameworks
  107. 107. Low level part • relatively thin layer on top of RestClient • store and retrieve JSON structures • query views the Couch way
  108. 108. Class mapping part • map Ruby classes to JSON documents • CRUD • declarative views with CouchDB semantics
  109. 109. RelaxDB • CRUD + very basic associations • automatic view generation via view_by • a bit of support for custom views via RelaxDB::View • CouchDB like view API
  110. 110. Couch Object • last updated in 2007 • pretty low level - okay for learning the details of Couch the DIY way • no update, no properties, no automatic view creation
  111. 111. Couch Potato • CRUD, associations + JSON mapping • built-in acts_as_versioned - 60 LOC but doing it by hand only requires 7 • ViewQuery class for creating/querying custom views • AR like finders
  112. 112. CouchFoo • takes ActiveRecord and makes it work with CouchDB • if you (have) to migrate an AR app... • doesn’t give you the power of CouchDB
  113. 113. ActiveCouch • “Object Relational Mapper for [..] CouchDB” • “Since, the Rubyists here at Wego are already very familiar with ActiveRecord semantics, care has been taken to ensure that ActiveCouch resembled it in many ways.”
  114. 114. ActiveCouch • one database per model • View class to upload #@!? views via Rake task • no support for custom views
  115. 115. Use the source
  116. 116. CouchRest Wiki
  117. 117. Page CRUD class Page < CouchRest::ExtendedDocument update_callback :after, :create_version property :title can’t infer attributes from table property :body view_by :title auto-generate simple views def create_version PageVersion.new(:page_id => id, :body => @body_was, :version => versions_count + 1).save! end create version on update end
  118. 118. PageVersion class PageVersion < CouchRest::ExtendedDocument property :body property :version property :page_id view_by [:page_id, :version] end
  119. 119. Word Count class WordCount < CouchRest::ExtendedDocument view_by :all, :map => quot;function(doc) { if(doc['couchrest-type'] == 'Page') { var words = doc.body.split(/W/); words.forEach(function(word) { if (word.length > 0) emit(word, 1); }); } }quot;, :reduce => quot;function(keys, values) { return sum(values); }quot; end
  120. 120. Querying Views Page.by_title Page.by_created_at(:limit => 1) PageVersion.get params[:id] Page.by_title(:key => title, :limit => 1).first WordCount.all
  121. 121. One more thing
  122. 122. CouchApp • serve entire apps directly from CouchDB • just JSON, HTML & JavaScript
  123. 123. What is CouchApp • bunch of Ruby Python scripts to help with development/deployment • data, CouchDB views, validations, shows, lists and assets in one database
  124. 124. AJAX apps • serve HTML, CSS as assets • do all the work in JavaScript • in the browser: GET from couch and append HTML, POST form data to CouchDB to update documents • in CouchDB: views to retrieve, compute data, validations
  125. 125. “real” apps • lists • shows • server HTML, XML etc. from CouchDB
  126. 126. Conclusion
  127. 127. DON’T use ActiveCouch unless you understand why it is the way it is or Couch Potato I’ll break all of its bones and APIS
  128. 128. DON’T or CouchFoo unless you want more power than AR can give you
  129. 129. Conclusion forgetting about the ActiveRecord way is more important than what framework
  130. 130. Conclusion think in documents & views, not in records and associations
  131. 131. Conclusion CouchDB is not about finding your records, it’s about clever map/reduce to get exactly what you want
  132. 132. What you want is a thin abstraction CouchDB semantics, not ActiveRecord start simple with CouchREST or RelaxDB
  133. 133. and relax... time to relax
  134. 134. Resources • The CouchDB book http://books.couchdb.org/relax/ • jchris CouchApp talk http://jchrisa.net/drl/CouchDB%20Talk%20at%20Vidoop/ VidoopCouchTalk.pdf • janl CouchDB talk http://www.slideshare.net/bbcwebdev/introduction-into-couchdb- jan-lehnardt-presentation • The example wiki http://github.com/langalex/couchdb_example_wiki/ • http://couch.io support, training, hosting, development
  135. 135. Questions? • Email: alex@upstream-berlin.com • Twitter: @langalex time to relax
  1. A particular slide catching your eye?

    Clipping is a handy way to collect important slides you want to go back to later.

×