Building Web Service Clients with ActiveModel
Upcoming SlideShare
Loading in...5
×
 

Like this? Share it with your network

Share

Building Web Service Clients with ActiveModel

on

  • 2,350 views

 

Statistics

Views

Total Views
2,350
Views on SlideShare
2,330
Embed Views
20

Actions

Likes
4
Downloads
16
Comments
0

1 Embed 20

http://www.slideshare.net 20

Accessibility

Categories

Upload Details

Uploaded via as Apple Keynote

Usage Rights

© All Rights Reserved

Report content

Flagged as inappropriate Flag as inappropriate
Flag as inappropriate

Select your reason for flagging this presentation as inappropriate.

Cancel
  • Full Name Full Name Comment goes here.
    Are you sure you want to
    Your message goes here
    Processing…
Post Comment
Edit your comment
  • <br />
  • <br />
  • <br />
  • <br />
  • <br />
  • <br />
  • <br />
  • <br />
  • <br />
  • <br />
  • <br />
  • <br />
  • <br />
  • <br />
  • <br />
  • <br />
  • <br />
  • <br />
  • <br />
  • <br />
  • <br />
  • <br />
  • <br />
  • <br />
  • <br />
  • <br />
  • <br />
  • <br />
  • <br />
  • <br />
  • <br />
  • <br />
  • <br />
  • <br />
  • <br />
  • <br />
  • <br />
  • <br />
  • <br />
  • <br />
  • <br />
  • <br />
  • <br />
  • <br />
  • <br />
  • <br />
  • <br />
  • <br />
  • <br />
  • <br />
  • <br />
  • <br />
  • <br />
  • <br />
  • <br />
  • <br />
  • <br />
  • <br />
  • <br />
  • <br />
  • <br />
  • <br />
  • <br />
  • <br />
  • <br />
  • <br />
  • <br />
  • <br />
  • <br />
  • <br />
  • <br />
  • <br />
  • <br />
  • <br />
  • <br />
  • <br />
  • <br />
  • <br />
  • <br />
  • <br />
  • <br />
  • <br />
  • <br />
  • <br />
  • <br />
  • <br />
  • <br />
  • <br />
  • <br />
  • <br />
  • <br />
  • <br />
  • <br />
  • <br />
  • <br />
  • <br />
  • <br />
  • <br />
  • <br />
  • <br />
  • <br />
  • <br />
  • <br />
  • <br />
  • <br />
  • <br />
  • <br />
  • <br />
  • <br />
  • <br />
  • <br />
  • <br />
  • <br />
  • <br />
  • <br />
  • <br />
  • <br />

Building Web Service Clients with ActiveModel Presentation Transcript

  • 1. Building Web Service Clients with ActiveModel Paul Dix http://pauldix.net @pauldix
  • 2. IM Paul Dix photo credit: Sebastian Delmont
  • 3. I am a Ruby love machine!
  • 4. Web Services, duh!
  • 5. ActiveModel
  • 6. Web Services Abstract Complexity
  • 7. Scale
  • 8. Scale with Complexity PhOtOnQuAnTiQuE (http://www.flickr.com/photos/67968452@N00/1876685709/)
  • 9. Scale with Team Size alexkess (http://www.flickr.com/photos/34838158@N00/3370167184/)
  • 10. Monolithic American Backroom (http://www.flickr.com/photos/41922098@N03/4247207167/)
  • 11. Split into Logical Parts
  • 12. How ActiveResource killed my best friend
  • 13. Brian Hathcock (http://www.flickr.com/photos/22961976@N00/3040920714/)
  • 14. Understandable Code
  • 15. Client libraries goal: readable and maintainable code
  • 16. Parallel Connections
  • 17. Make Stubbing Easy for Development
  • 18. define:”Web Services”
  • 19. External Services
  • 20. Internal Services
  • 21. ActiveModel is for use with rails forms helpers and other things. Things that are only used inside user requests. Calls Inside User Requests
  • 22. focus(:internal_services)
  • 23. Abstracting Complexity
  • 24. Work with large code base
  • 25. Scale
  • 26. Not Traffic
  • 27. NoSQL is getting there
  • 28. Code Complexity
  • 29. Team Size
  • 30. Examples
  • 31. Processor
  • 32. Operating System
  • 33. MapReduce
  • 34. Web Services?
  • 35. Email Service
  • 36. User Service
  • 37. Haystack
  • 38. Indexing
  • 39. How to separate functionality
  • 40. Partition on Iteration Speed
  • 41. Partition on Logical Fucntion
  • 42. Partition on Read/Write Frequencies
  • 43. Partition on Join Frequency
  • 44. Goals
  • 45. Denormalize and Replicate
  • 46. Separation of Concerns
  • 47. Abstraction
  • 48. ActiveResource and ActiveRecord killed these
  • 49. Both make connections inside the model
  • 50. class Collect < Base end class ShippingAddress < Base end class BillingAddress < Base end class LineItem < Base end class ShippingLine < Base end class NoteAttribute < Base end
  • 51. lloydi (http://www.flickr.com/photos/58944004@N00/2362260604/)
  • 52. class Collect < Base end class ShippingAddress < Base end class BillingAddress < Base end class LineItem < Base end class ShippingLine < Base end class NoteAttribute < Base end
  • 53. Makes requests serially
  • 54. Requests in Parallel
  • 55. ActiveModel
  • 56. helpers for adding prefixes and suffixes to methods.... boring AttributeMethods
  • 57. Callbacks
  • 58. class User include ActiveModel::Callbacks before_create :do_stuff def create # ... end def do_stuff # ... end end
  • 59. Dirty Tracking
  • 60. class Person include ActiveModel::Dirty define_attribute_methods [:name] def name @name end def name=(val) name_will_change! @name = val end def save @previously_changed = changes end end
  • 61. # A newly instantiated object is unchanged: person = Person.find_by_name('Uncle Bob') person.changed? # => false
  • 62. # Change the name: person.name = 'Bob' person.changed? # => true person.name_changed? # => true person.name_was # => 'Uncle Bob' person.name_change # => ['Uncle Bob', 'Bob'] person.name = 'Bill' person.name_change # => ['Uncle Bob', 'Bill']
  • 63. # Save the changes: person.save person.changed? # => false person.name_changed? # => false
  • 64. # Assigning the same value leaves the # attribute unchanged: person.name = 'Bill' person.name_changed? # => false person.name_change # => nil
  • 65. # Which attributes have changed? person.name = 'Bob' person.changed # => ['name'] person.changes # => {'name' => ['Bill', 'Bob']}
  • 66. # Resetting an attribute returns it to # its original state: person.reset_name! # => 'Bill' person.changed? # => false person.name_changed? # => false person.name # => 'Bill'
  • 67. Errors
  • 68. class User def errors @errors ||= ActiveModel::Errors.new(self) end def validate! errors.add(:name, "can not be nil") end end user.errors[:name] #=> ["can not be nil"]
  • 69. Serialization
  • 70. class User include ActiveModel::Serialization def attributes { :id => @id, :name => @name, :email => @email } end end user.to_json(:only => [:id, :name]) user.to_xml(:except => [:email])
  • 71. Validations
  • 72. class User include ActiveModel::Validations attr_reader :name, :email, :age, :terms_of_service, :password, :password_confirmation, :role validates_acceptance_of :terms_of_service end user = User.new puts user.valid?
  • 73. class User include ActiveModel::Validations attr_reader :name, :email, :age, :terms_of_service, :password, :password_confirmation, :role validates_confirmation_of :password end user = User.new puts user.valid?
  • 74. class User include ActiveModel::Validations attr_reader :name, :email, :age, :terms_of_service, :password, :password_confirmation, :role validates_presence_of :name end user = User.new puts user.valid?
  • 75. class User include ActiveModel::Validations attr_reader :name, :email, :age, :terms_of_service, :password, :password_confirmation, :role validates_exclusion_of :name, :in => ["admin"] end user = User.new puts user.valid?
  • 76. class User include ActiveModel::Validations attr_reader :name, :email, :age, :terms_of_service, :password, :password_confirmation, :role validates_inclusion_of :role, :in => ["user", "admin"] end user = User.new puts user.valid?
  • 77. class User include ActiveModel::Validations attr_reader :name, :email, :age, :terms_of_service, :password, :password_confirmation, :role validates_format_of :email, :with => /A([^@s]+)@((?:[-a-z0-9]+.)+[a-z]{2,})Z/i end user = User.new puts user.valid?
  • 78. class User include ActiveModel::Validations attr_reader :name, :email, :age, :terms_of_service, :password, :password_confirmation, :role validates_length_of :password, :minimum => 6 end user = User.new puts user.valid?
  • 79. class User include ActiveModel::Validations attr_reader :name, :email, :age, :terms_of_service, :password, :password_confirmation, :role validates_numericality_of :age end user = User.new puts user.valid?
  • 80. validates_uniqueness_of?
  • 81. ehpien (http://www.flickr.com/photos/91499534@N00/343313257/)
  • 82. Testing
  • 83. require 'rubygems' require 'active_model' require 'test/unit' require 'user' class LintTest < ActiveModel::TestCase include ActiveModel::Lint::Tests def setup @model = User.new end end
  • 84. class User include ActiveModel::Conversion extend ActiveModel::Naming def valid?() true end def errors @errors ||= ActiveModel::Errors.new(self) end def persisted? true end end
  • 85. Parallel Connections
  • 86. Asynchronous
  • 87. EventMachine
  • 88. Curb
  • 89. Typhoeus Mushkush (http://www.flickr.com/photos/43002463@N00/2877016310/)
  • 90. Quick Example
  • 91. PauldixReadingList::ReadingList.for_user( "paul", :include => [:entry, :rating_total]) do |list| reading_list = list end HYDRA.run # now we can access the reading list reading_list.entries.each do |entry| puts entry.id puts entry.title puts entry.body puts "up: #{entry.rating_total.up_count} | down: #{entry.rating_total.down_count}nn" end
  • 92. def self.for_user(user_id, options = {}, &block) includes = options[:include] || [] request = Typhoeus::Request.new(get_by_id_uri(user_id)) request.on_complete do |response| list = new(response.body, options) list.request_entries if includes.include?(:entry) list.request_rating_totals if includes.include?(:rating_total) block.call(list) end PauldixReadingList::Config.hydra.queue(request) end
  • 93. def self.get_ids(ids, &block) request = Typhoeus::Request.new(get_ids_uri(ids)) request.on_complete do |response| json = Yajl::Parser.parse(response.body) entries = ids.map do |id| new(json[id].merge("id" => id)) end block.call(entries) end PauldixEntries::Config.hydra.queue(request) end
  • 94. def self.get_ids(ids, &block) request = Typhoeus::Request.new(get_ids_uri(ids)) request.on_complete do |response| json = Yajl::Parser.parse(response.body) ratings = ids.map do |id| new(json[id]) end block.call(ratings) end PauldixRatings::Config.hydra.queue(request) end
  • 95. Gunnsi (http://www.flickr.com/photos/38735097@N00/440198755/)
  • 96. Threaded
  • 97. require 'net/http' include Java import 'java.util.concurrent.Executors' class Request include java.util.concurrent.Callable def initialize(url) @url = url end def call Net::HTTP.get(URI.parse(@url)) end end
  • 98. thread_pool = Executors.new_fixed_thread_pool(50) futures = [] 100.times do |i| request = Request.new("http://localhost:3000/entries/#{i}") futures << thread_pool.submit(request) end results = futures.map {|f| f.get} # do something with results thread_pool.shutdown
  • 99. Keep Alive
  • 100. Awesome art credit: Joe West
  • 101. Stubbing
  • 102. Review
  • 103. Readable Client Code
  • 104. lloydi (http://www.flickr.com/photos/58944004@N00/2362260604/)
  • 105. Models Build Requests
  • 106. Parallel Connections
  • 107. Validate Early
  • 108. Easy Stubs
  • 109. Abstract Complexity
  • 110. Scale
  • 111. Scale with Complexity PhOtOnQuAnTiQuE (http://www.flickr.com/photos/67968452@N00/1876685709/)
  • 112. Scale with Team Size alexkess (http://www.flickr.com/photos/34838158@N00/3370167184/)
  • 113. Monolithic American Backroom (http://www.flickr.com/photos/41922098@N03/4247207167/)
  • 114. Thanks!
  • 115. Questions?