ruby sittin' on the couch

Download Ruby sittin' on the Couch

If you can't read please download the document

Upload: langalex

Post on 29-Jan-2015

108 views

Category:

Technology


1 download

DESCRIPTION

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.

TRANSCRIPT

  • 1. * #sor09

2. Ruby sittin on the Couch 3. About me Alexander Lang Upstream Agile GmbH, Berlin programmer, owner http://upstream-berlin.com 4. 11/52 5. Web development w/ Ruby 6. BDD 7. Buzzword DrivenDevelopment 8. TDD BDDagile Pair Programming * all the f****** time 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. Who are you? 11. Who is in this room? Chris Anderson George Palmer Paul Carey Johan Srensen Cheah Chu Yeow/Carlos Villela 12. Who is in this room? Chris Anderson (couchrest + couchapp) George Palmer (couch_foo) Paul Carey (relaxdb) Johan Srensen (couchbject) Cheah Chu Yeow/Carlos Villela (activecouch) 13. Forget it! 14. Agenda CouchDB introduction The CouchDB example wiki The frameworks Conclusion: where to go from here? Q &A 15. CouchDB introduction 16. What is CouchDB? 17. Apache Projectso it has to be good 18. Document oriented Database 19. Store/read any JSONdocument 20. Powerful map/reduceviews for querying** well see what that is 21. Why CouchDB? 22. Buzzword compliant 23. JavaScript 24. REST HTTP interface 25. JSON 26. Map/Reduce the thing that made Google rich 27. Fun ! 28. No more SQL/Schema/ Migrations 29. JavaScript views instead 30. Simple! 31. HTTP interface 32. can use existing clients, libraries 33. It scales 34. just like Ruby :) 35. No locks, instead MVCC 36. integrated replication (yes, multi master) 37. use existing load balancer, proxies etc. HTTP ftw 38. and so on... 39. So how does Couch work? 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. 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. 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. Map/Reduce views { title: page one, tags: [rst, important] }{ title: page 2, tags: [funny] } 44. Map/Reduce views {function(doc) { title: page one,emit(doc.title, doc.tags.length) tags: [rst, important]} }{ title: page 2, tags: [funny] } 45. Map/Reduce views {function(doc) { title: page one,emit(doc.title, doc.tags.length) tags: [rst, important]} } keyvalue {page one2 title: page 2, tags: [funny] page 2 1 } 46. Map/Reduce views {function(doc) { title: page one,emit(doc.title, doc.tags.length) tags: [rst, important]} } keyvalue {page one2 title: page 2, tags: [funny] page 2 1 } function(keys, values) {return sum(values);} 47. Map/Reduce views {function(doc) { title: page one,emit(doc.title, doc.tags.length) tags: [rst, important]} } keyvalue {page one2 title: page 2, tags: [funny] page 2 1 } function(keys, values) {return sum(values); 3} 48. Query a View 49. Query a View/my_db/_design/wiki/_view/tags_count 50. Query a View/my_db/_design/wiki/_view/tags_count /my_db/_design/wiki/_view/tags_count?reduce=false 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. 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. 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. Query a View 55. Query a View ?key=page one 56. Query a View ?key=page one ?startkey=page 1&endkey=page 999 57. Query a View ?key=page one ?startkey=page 1&endkey=page 999 ?key=[composite, key] 58. Query a View?key=page one ?startkey=page 1&endkey=page 999 ?key=[composite, key]?keys=[set, of, keys] 59. Query a View?key=page one ?startkey=page 1&endkey=page 999 ?key=[composite, key]?keys=[set, of, keys] 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. The CouchDB example wiki 62. Example Wiki ActiveRecord RelaxDB CouchRest Couch Potato ActiveCouch CouchOject CouchFoo CouchApp 63. a wiki example app implemented in all frameworks I could nd + in ActiveRecord for comparisonDISCLAIMER: implementations are insecure, have bugs and arent meant for production at all 64. http://github.com/langalex/couchdb_example_wiki 65. Example Wiki a few simple features create a page add new pages by clicking on a CamelCase link list of pages 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. Example Wiki creating pages is easy versioning, statistics harder views are the source of CouchDBs power 68. let me show you how it works Example Wiki 69. ActiveRecord Wiki 70. routes.rb map.resources :pages do |pages| pages.resources :versions endmap.resources :statistics map.root :controller => quot;pagesquot;, :action => 'show' 71. page.rb class Page < ActiveRecord::Base acts_as_versioneddef to_param title end end 72. pages/show.html.erb def linkify(text) text.gsub(/([A-Z][a-z]+([A-Z][a-z]+)+)/) do link_to($1, page_path($1)) end endreplace CamelCase words with links to #show 73. pages_controller.rbdef show @page = Page.first unless params[:id] @page ||= Page.find_by_title params[:id] redirect_to new_page_path(:title => params[:id]) unless @page endredirect to #new if no page found 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. schema.rb create_table quot;page_versionsquot;, :force => true do |t| t.integerquot;page_idquot; t.integerquot;versionquot; t.text quot;bodyquot; t.datetime quot;created_atquot; t.datetime quot;updated_atquot; endcreate_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.integerquot;versionquot;,:default => 1 end 76. AR Summary Page has_many PageVersions ugly schema with duplicated table acts_as_versioned does the magic for us statistics - ?!? 77. CouchDB Wiki How does it work? 78. The Page { _id: 89765, _rev: lb7tlb, type: Page, title: page one, body: this is page one } 79. Page Versions { _id: 765, _rev: lhjb97 type: PageVersion, title: page one, body: this is page one, version: 23, page_id: 89765 } 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 onepage_id: 89765 }{} }_id: 6437,_rev: lhjb97 {type: PageVersion, _id: 6367,title: page one, { { _rev: lhjb97body: 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 onebody: this is page one } } 81. Finding pages function(doc) { key value if(doc.type == Page) { emit(doc.title, doc); page 2{...} } }page one {...} 82. Finding Page Versions function(doc) { if(doc.type == PageVersion) { emit([doc.page_id, doc.version], doc); } }keyvalue [ladsb7gi, 1] {...} [ladsb7gi, 2] {...} [nloh79d, 1]{...} 83. Finding Page Versionskeyvalue [ladsb7gi, 1] {...} [ladsb7gi, 2] {...} [nloh79d, 1]{...} GET /mydb/_design/page_versions/_view/by_page?startkey=[ladsb7gi, 1]&endkey=[ ladsb7gi,{}] 84. Counting Words - Map 85. Counting Words - Map{body: page one}{body: page 2} 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. 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); });}} keyvalue page1 {body: page one} page1{body: page 2} one 121 88. Counting Words - reduce 89. Counting Words - reducekey value page 1 page 1 one12 1 90. Counting Words - reduce keyvaluepage1page1one 1 21 function(keys, values) { return sum(values); } 91. Counting Words - reduce keyvaluepage1page1one 1 21 key valuepage2 function(keys, values) { return sum(values);one 1 }21 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. Show us the frameworks already 94. Whats the frameworks job? 95. Whats the frameworks job? ActiveRecord 96. Whats the frameworks job?ActiveRecord map objects to relations and back do the whole SQL thing 97. Whats the frameworks job? ActiveRecord schema attribute auto tracking detection serialized attributes pagination groupsJOINS uniquelazy loadingcaching map objects to relations and back count do the whole SQL thing HABTM create or update? has_many :through conditionseager association loading connection DDL:dependent => :destroy 98. Whats the frameworks job? ActiveRecordPage.all :include => :tagsSELECT pages.id ... JOIN tags ON ... WHERE ...... [10 more lines] ... 99. Whats the frameworks job? ActiveRecordbig fat abstraction SQL 100. Whats the frameworks job?ActiveCouchRelaxFooDBObject 101. Whats the frameworks job?ActiveCouchRelaxFooDBObject {type: Page, title: page one} 102. Whats the frameworks job?ActiveCouchRelaxFooDBObject POST /mydb/, {title: page one, type: Page}GET /mydb/page-one 103. Whats the frameworks job?ActiveCouchRelaxFooDBObject skinnyCouchDBabstraction 104. ActiveCouchRelaxFooDBObject ... are not *that* important 105. The frameworks CouchPoatoRelaxDB CouchObject ActiveCouch CouchRest CouchFoo 106. CouchRest 2 in 1 foundation for most other frameworks 107. Low level part relatively thin layer on top of RestClient store and retrieve JSON structures query views the Couch way 108. Class mapping part map Ruby classes to JSON documents CRUD declarative views with CouchDB semantics 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. 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. 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 nders 112. CouchFoo takes ActiveRecord and makes it work with CouchDB if you (have) to migrate an AR app... doesnt give you the power of CouchDB 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. ActiveCouch one database per model View class to upload #@!? views via Rake task no support for custom views 115. Use the source 116. CouchRest Wiki 117. Page CRUD class Page < CouchRest::ExtendedDocument update_callback :after, :create_versionproperty :titlecant infer attributes from table property :bodyview_by :titleauto-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. PageVersionclass PageVersion < CouchRest::ExtendedDocument property :body property :version property :page_idview_by [:page_id, :version] end 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. Querying Views Page.by_titlePage.by_created_at(:limit => 1)PageVersion.get params[:id]Page.by_title(:key => title, :limit => 1).firstWordCount.all 121. One more thing 122. CouchApp serve entire apps directly from CouchDB just JSON, HTML & JavaScript 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. 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. real apps lists shows server HTML, XML etc. from CouchDB 126. Conclusion 127. DONTuse ActiveCouch unless you understand why it is the way it isor Couch Potato Ill break all of its bones and APIS 128. DONT or CouchFoo unless you want more power than AR can give you 129. Conclusion forgetting about the ActiveRecord way is more important than what framework 130. Conclusion think in documents & views, not in records and associations 131. Conclusion CouchDB is not about nding your records, its about clever map/reduce to get exactly what you want 132. What you want is a thin abstraction CouchDB semantics, not ActiveRecord start simple with CouchREST or RelaxDB 133. and relax...time to relax 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. Questions? Email: [email protected] Twitter: @langalextime to relax