Your SlideShare is downloading. ×
0
Building Web Service
     Clients with
    ActiveModel
          Paul Dix
      http://pauldix.net
          @pauldix
IM Paul Dix




  photo credit: Sebastian Delmont
I am a Ruby love
    machine!
Web Services, duh!
ActiveModel
Web Services Abstract
    Complexity
Scale
Scale with Complexity

PhOtOnQuAnTiQuE (http://www.flickr.com/photos/67968452@N00/1876685709/)
Scale with Team Size
alexkess (http://www.flickr.com/photos/34838158@N00/3370167184/)
Monolithic




  American Backroom (http://www.flickr.com/photos/41922098@N03/4247207167/)
Split into Logical Parts
How ActiveResource
killed my best friend
Brian Hathcock (http://www.flickr.com/photos/22961976@N00/3040920714/)
Understandable Code
Client libraries goal:
    readable and
 maintainable code
Parallel Connections
Make Stubbing Easy for
    Development
define:”Web Services”
External
Services
Internal
Services
ActiveModel is for use
with rails forms helpers
and other things. Things
that are only used inside
user requests.




    ...
focus(:internal_services)
Abstracting Complexity
Work with large code
       base
Scale
Not Traffic
NoSQL is getting there
Code Complexity
Team Size
Examples
Processor
Operating System
MapReduce
Web Services?
Email Service
User Service
Haystack
Indexing
How to separate
 functionality
Partition on Iteration
        Speed
Partition on Logical
      Fucntion
Partition on Read/Write
       Frequencies
Partition on Join
   Frequency
Goals
Denormalize and
   Replicate
Separation of Concerns
Abstraction
ActiveResource and
ActiveRecord killed
       these
Both make connections
   inside the model
class Collect < Base
end

class ShippingAddress < Base
end

class BillingAddress < Base
end

class LineItem < Base
end

cl...
lloydi (http://www.flickr.com/photos/58944004@N00/2362260604/)
class Collect < Base
end

class ShippingAddress < Base
end

class BillingAddress < Base
end

class LineItem < Base
end

cl...
Makes requests serially
Requests in Parallel
ActiveModel
helpers for adding
prefixes and suffixes to
methods.... boring




              AttributeMethods
Callbacks
class User
  include ActiveModel::Callbacks

 before_create :do_stuff

  def create
    # ...
  end

  def do_stuff
    # ...
Dirty Tracking
class Person
  include ActiveModel::Dirty

 define_attribute_methods [:name]

  def name
    @name
  end

  def name=(val)...
# A newly instantiated object is unchanged:
person = Person.find_by_name('Uncle Bob')
person.changed?       # => false
# Change the name:
person.name = 'Bob'
person.changed?        #   =>   true
person.name_changed?   #   =>   true
person.na...
# Save the changes:
person.save
person.changed?        # => false
person.name_changed?   # => false
# Assigning the same value leaves the
# attribute unchanged:
person.name = 'Bill'
person.name_changed? # => false
person.n...
# Which attributes have changed?
person.name = 'Bob'
person.changed      # => ['name']
person.changes      # => {'name' =>...
# Resetting an attribute returns it to
# its original state:
person.reset_name!    # => 'Bill'
person.changed?       # => ...
Errors
class User
  def errors
    @errors ||= ActiveModel::Errors.new(self)
  end

  def validate!
    errors.add(:name, "can no...
Serialization
class User
  include ActiveModel::Serialization

  def attributes
    {
      :id => @id,
      :name => @name,
      :ema...
Validations
class User
  include ActiveModel::Validations
  attr_reader :name, :email, :age,
              :terms_of_service, :passwor...
class User
  include ActiveModel::Validations
  attr_reader :name, :email, :age,
              :terms_of_service, :passwor...
class User
  include ActiveModel::Validations
  attr_reader :name, :email, :age,
              :terms_of_service, :passwor...
class User
  include ActiveModel::Validations
  attr_reader :name, :email, :age,
              :terms_of_service, :passwor...
class User
  include ActiveModel::Validations
  attr_reader :name, :email, :age,
              :terms_of_service, :passwor...
class User
  include ActiveModel::Validations
  attr_reader :name, :email, :age,
              :terms_of_service, :passwor...
class User
  include ActiveModel::Validations
  attr_reader :name, :email, :age,
              :terms_of_service, :passwor...
class User
  include ActiveModel::Validations
  attr_reader :name, :email, :age,
              :terms_of_service, :passwor...
validates_uniqueness_of?
ehpien (http://www.flickr.com/photos/91499534@N00/343313257/)
Testing
require   'rubygems'
require   'active_model'
require   'test/unit'
require   'user'

class LintTest < ActiveModel::TestCa...
class User
  include ActiveModel::Conversion
  extend ActiveModel::Naming

  def valid?() true end

  def errors
    @erro...
Parallel Connections
Asynchronous
EventMachine
Curb
Typhoeus




Mushkush (http://www.flickr.com/photos/43002463@N00/2877016310/)
Quick Example
PauldixReadingList::ReadingList.for_user(
  "paul",
  :include => [:entry, :rating_total]) do |list|

  reading_list = lis...
def self.for_user(user_id, options = {}, &block)
  includes = options[:include] || []

 request =
   Typhoeus::Request.new...
def self.get_ids(ids, &block)
  request = Typhoeus::Request.new(get_ids_uri(ids))

 request.on_complete do |response|
   j...
def self.get_ids(ids, &block)
  request = Typhoeus::Request.new(get_ids_uri(ids))

 request.on_complete do |response|
   j...
Gunnsi (http://www.flickr.com/photos/38735097@N00/440198755/)
Threaded
require 'net/http'
include Java
import 'java.util.concurrent.Executors'

class Request
  include java.util.concurrent.Call...
thread_pool = Executors.new_fixed_thread_pool(50)

futures = []
100.times do |i|
  request =
Request.new("http://localhost...
Keep Alive
Awesome art credit: Joe West
Stubbing
Review
Readable Client Code
lloydi (http://www.flickr.com/photos/58944004@N00/2362260604/)
Models Build Requests
Parallel Connections
Validate Early
Easy Stubs
Abstract Complexity
Scale
Scale with Complexity

PhOtOnQuAnTiQuE (http://www.flickr.com/photos/67968452@N00/1876685709/)
Scale with Team Size
alexkess (http://www.flickr.com/photos/34838158@N00/3370167184/)
Monolithic




  American Backroom (http://www.flickr.com/photos/41922098@N03/4247207167/)
Thanks!
Questions?
Building Web Service Clients with ActiveModel
Building Web Service Clients with ActiveModel
Upcoming SlideShare
Loading in...5
×

Building Web Service Clients with ActiveModel

1,883

Published on

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

No Downloads
Views
Total Views
1,883
On Slideshare
0
From Embeds
0
Number of Embeds
0
Actions
Shares
0
Downloads
18
Comments
0
Likes
5
Embeds 0
No embeds

No notes for slide





















































































































  • Transcript of "Building Web Service Clients with ActiveModel"

    1. 1. Building Web Service Clients with ActiveModel Paul Dix http://pauldix.net @pauldix
    2. 2. IM Paul Dix photo credit: Sebastian Delmont
    3. 3. I am a Ruby love machine!
    4. 4. Web Services, duh!
    5. 5. ActiveModel
    6. 6. Web Services Abstract Complexity
    7. 7. Scale
    8. 8. Scale with Complexity PhOtOnQuAnTiQuE (http://www.flickr.com/photos/67968452@N00/1876685709/)
    9. 9. Scale with Team Size alexkess (http://www.flickr.com/photos/34838158@N00/3370167184/)
    10. 10. Monolithic American Backroom (http://www.flickr.com/photos/41922098@N03/4247207167/)
    11. 11. Split into Logical Parts
    12. 12. How ActiveResource killed my best friend
    13. 13. Brian Hathcock (http://www.flickr.com/photos/22961976@N00/3040920714/)
    14. 14. Understandable Code
    15. 15. Client libraries goal: readable and maintainable code
    16. 16. Parallel Connections
    17. 17. Make Stubbing Easy for Development
    18. 18. define:”Web Services”
    19. 19. External Services
    20. 20. Internal Services
    21. 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. 22. focus(:internal_services)
    23. 23. Abstracting Complexity
    24. 24. Work with large code base
    25. 25. Scale
    26. 26. Not Traffic
    27. 27. NoSQL is getting there
    28. 28. Code Complexity
    29. 29. Team Size
    30. 30. Examples
    31. 31. Processor
    32. 32. Operating System
    33. 33. MapReduce
    34. 34. Web Services?
    35. 35. Email Service
    36. 36. User Service
    37. 37. Haystack
    38. 38. Indexing
    39. 39. How to separate functionality
    40. 40. Partition on Iteration Speed
    41. 41. Partition on Logical Fucntion
    42. 42. Partition on Read/Write Frequencies
    43. 43. Partition on Join Frequency
    44. 44. Goals
    45. 45. Denormalize and Replicate
    46. 46. Separation of Concerns
    47. 47. Abstraction
    48. 48. ActiveResource and ActiveRecord killed these
    49. 49. Both make connections inside the model
    50. 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. 51. lloydi (http://www.flickr.com/photos/58944004@N00/2362260604/)
    52. 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. 53. Makes requests serially
    54. 54. Requests in Parallel
    55. 55. ActiveModel
    56. 56. helpers for adding prefixes and suffixes to methods.... boring AttributeMethods
    57. 57. Callbacks
    58. 58. class User include ActiveModel::Callbacks before_create :do_stuff def create # ... end def do_stuff # ... end end
    59. 59. Dirty Tracking
    60. 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. 61. # A newly instantiated object is unchanged: person = Person.find_by_name('Uncle Bob') person.changed? # => false
    62. 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. 63. # Save the changes: person.save person.changed? # => false person.name_changed? # => false
    64. 64. # Assigning the same value leaves the # attribute unchanged: person.name = 'Bill' person.name_changed? # => false person.name_change # => nil
    65. 65. # Which attributes have changed? person.name = 'Bob' person.changed # => ['name'] person.changes # => {'name' => ['Bill', 'Bob']}
    66. 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. 67. Errors
    68. 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. 69. Serialization
    70. 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. 71. Validations
    72. 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. 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. 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. 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. 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. 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. 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. 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. 80. validates_uniqueness_of?
    81. 81. ehpien (http://www.flickr.com/photos/91499534@N00/343313257/)
    82. 82. Testing
    83. 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. 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. 85. Parallel Connections
    86. 86. Asynchronous
    87. 87. EventMachine
    88. 88. Curb
    89. 89. Typhoeus Mushkush (http://www.flickr.com/photos/43002463@N00/2877016310/)
    90. 90. Quick Example
    91. 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. 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. 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. 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. 95. Gunnsi (http://www.flickr.com/photos/38735097@N00/440198755/)
    96. 96. Threaded
    97. 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. 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. 99. Keep Alive
    100. 100. Awesome art credit: Joe West
    101. 101. Stubbing
    102. 102. Review
    103. 103. Readable Client Code
    104. 104. lloydi (http://www.flickr.com/photos/58944004@N00/2362260604/)
    105. 105. Models Build Requests
    106. 106. Parallel Connections
    107. 107. Validate Early
    108. 108. Easy Stubs
    109. 109. Abstract Complexity
    110. 110. Scale
    111. 111. Scale with Complexity PhOtOnQuAnTiQuE (http://www.flickr.com/photos/67968452@N00/1876685709/)
    112. 112. Scale with Team Size alexkess (http://www.flickr.com/photos/34838158@N00/3370167184/)
    113. 113. Monolithic American Backroom (http://www.flickr.com/photos/41922098@N03/4247207167/)
    114. 114. Thanks!
    115. 115. Questions?
    1. A particular slide catching your eye?

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

    ×