SlideShare une entreprise Scribd logo
1  sur  83
Télécharger pour lire hors ligne
Synchronizing Core
                       Data With Rails
                            Ken Collins
                           metaskills.net




Wednesday, July 14, 2010
Wednesday, July 14, 2010
Wednesday, July 14, 2010
Why Write Web
                    Applications For The
                         Web Only?



Wednesday, July 14, 2010
Why Write Web
                    Applications For The
                     Web <html> Only?



Wednesday, July 14, 2010
Why Write Web
                    Applications For The
                     Web <html> Only?
               THE BACK-END (server)

                   Rails Web Application




Wednesday, July 14, 2010
Why Write Web
                    Applications For The
                     Web <html> Only?
               THE BACK-END (server)       THE FRONT-END (clients)

                   Rails Web Application     Browser - JavaScript
                                              iPhone - Objective-C




Wednesday, July 14, 2010
Why Write Web
                    Applications For The
                     Web <html> Only?
               THE BACK-END (server)       THE FRONT-END (clients)

                   Rails Web Application     Browser - JavaScript
                                              iPhone - Objective-C




Wednesday, July 14, 2010
The "AJAX Head"
                            Design Pattern




Wednesday, July 14, 2010
The "AJAX Head"
                            Design Pattern




Wednesday, July 14, 2010
The "AJAX Head"
                            Design Pattern
                             “e AJAX head design pattern forces the view and
                            controller to work in isolation with the most minimal
                               coupling possible. Kind of like a web service.”

                               “...an implementation pattern that drastically
                             modi es common web client-server interactions in
                               order to bring them more closely in line with
                                    enterprise client-server interactions...”




Wednesday, July 14, 2010
The "AJAX Head"
                                  Design Pattern
                                         “e AJAX head design pattern forces the view and
                                        controller to work in isolation with the most minimal
                                           coupling possible. Kind of like a web service.”

                                            “...an implementation pattern that drastically
                                          modi es common web client-server interactions in
                                            order to bring them more closely in line with
                                                 enterprise client-server interactions...”



                                    http://voodootikigod.com/ajax-head-design-pattern
                             http://metaskills.net/2008/5/24/the-ajax-head-br-design-pattern
                           http://metaskills.net/2008/6/18/restful-ajax-with-forgery-protection

Wednesday, July 14, 2010
Why Write Web
                    Applications For The
                     Web <html> Only?
               THE BACK-END (server)       THE FRONT-END (clients)

                   Rails Web Application     Browser - JavaScript
                                              iPhone - Objective-C




Wednesday, July 14, 2010
Why Write Web
                    Applications For The
                     Web <html> Only?
               THE BACK-END (server)       THE FRONT-END (clients)

                   Rails Web Application     Browser - JavaScript
                                              iPhone - Objective-C
                           1) AR Model
                           2) Controller


Wednesday, July 14, 2010
Why Write Web
                    Applications For The
                     Web <html> Only?
               THE BACK-END (server)       THE FRONT-END (clients)

                   Rails Web Application     Browser - JavaScript
                                              iPhone - Objective-C
                           1) AR Model        1) CoreData Models
                           2) Controller      2) External API


Wednesday, July 14, 2010
The Backend
                             ( part 1 - web app model )




Wednesday, July 14, 2010
Wednesday, July 14, 2010
.0.b e t a4
                           3.0




Wednesday, July 14, 2010
.0.b e t a4
                           3.0




Wednesday, July 14, 2010
.0.b e t a4
                           3.0




Wednesday, July 14, 2010
Data-Interchange... JSON




Wednesday, July 14, 2010
Data-Interchange... JSON
            JSON (JavaScript Object Notation) is a lightweight format. It is easy for humans to read and
             write. It is easy for machines to parse and generate. JSON is a text format that is completely
            language independent but uses conventions that are familiar to programmers of the C-family
                of languages, including C, C++, C#, Java, JavaScript, Perl, Python, and many others.




Wednesday, July 14, 2010
Data-Interchange... JSON
            JSON (JavaScript Object Notation) is a lightweight format. It is easy for humans to read and
             write. It is easy for machines to parse and generate. JSON is a text format that is completely
            language independent but uses conventions that are familiar to programmers of the C-family
                of languages, including C, C++, C#, Java, JavaScript, Perl, Python, and many others.




                           http://www.json.org/

Wednesday, July 14, 2010
JSON in Ruby/Rails
                                   class Object
                                     def to_json(options = nil)
                                       ActiveSupport::JSON.encode(
                                        self,options)
                                     end
                                     def as_json(options = nil)
                                       instance_values
                                     end
                                   end

                                   class Foo
                                     attr_accessor :bar
                                   end

                                   f = Foo.new
                                   f.bar = 'batz'
                                   puts f.to_json   # => {"bar":"batz"}




Wednesday, July 14, 2010
JSON in Ruby/Rails
            Specifically in ActiveSupport
            require 'active_support/json'   class Object
                                              def to_json(options = nil)
                                                ActiveSupport::JSON.encode(
                                                 self,options)
                                              end
                                              def as_json(options = nil)
                                                instance_values
                                              end
                                            end

                                            class Foo
                                              attr_accessor :bar
                                            end

                                            f = Foo.new
                                            f.bar = 'batz'
                                            puts f.to_json   # => {"bar":"batz"}




Wednesday, July 14, 2010
JSON in Ruby/Rails
            Specifically in ActiveSupport
            require 'active_support/json'              class Object
                                                         def to_json(options = nil)
            Object#to_json calls #as_json to               ActiveSupport::JSON.encode(
            coerce itself into something natively           self,options)
            encodable like Hash, Integer, or String.     end
            Override #as_json instead of #to_json        def as_json(options = nil)
            so you're JSON library agnostic.               instance_values
                                                         end
                                                       end

                                                       class Foo
                                                         attr_accessor :bar
                                                       end

                                                       f = Foo.new
                                                       f.bar = 'batz'
                                                       puts f.to_json   # => {"bar":"batz"}




Wednesday, July 14, 2010
JSON in Ruby/Rails
            Specifically in ActiveSupport
            require 'active_support/json'              class Object
                                                         def to_json(options = nil)
            Object#to_json calls #as_json to               ActiveSupport::JSON.encode(
            coerce itself into something natively           self,options)
            encodable like Hash, Integer, or String.     end
            Override #as_json instead of #to_json        def as_json(options = nil)
            so you're JSON library agnostic.               instance_values
                                                         end
            ActiveSupport::JSON does all the work      end
            of defining #as_json on all core ruby
            objects. It also abstracts out decoding    class Foo
            with hot swappable backends using            attr_accessor :bar
            ActiveSupport::JSON.backend =              end
            JSONGem'.
            '
                                                       f = Foo.new
                                                       f.bar = 'batz'
                                                       puts f.to_json   # => {"bar":"batz"}




Wednesday, July 14, 2010
JSON in Ruby/Rails
            Specifically in ActiveSupport
            require 'active_support/json'              class Object
                                                         def to_json(options = nil)
            Object#to_json calls #as_json to               ActiveSupport::JSON.encode(
            coerce itself into something natively           self,options)
            encodable like Hash, Integer, or String.     end
            Override #as_json instead of #to_json        def as_json(options = nil)
            so you're JSON library agnostic.               instance_values
                                                         end
            ActiveSupport::JSON does all the work      end
            of defining #as_json on all core ruby
            objects. It also abstracts out decoding    class Foo
            with hot swappable backends using            attr_accessor :bar
            ActiveSupport::JSON.backend =              end
            JSONGem'.
            '
                                                       f = Foo.new
            In rails, with ActiveSupport, primitive    f.bar = 'batz'
            ruby objects serialize their instance      puts f.to_json   # => {"bar":"batz"}
            variables using another core extension
            Object#instance_values which returns
            a Hash of said ivars.


Wednesday, July 14, 2010
JSON in ActiveRecord
                  class Bookmark < ActiveRecord::Base

                      JSON_ATTRS = ['id','owner_id','owner_type','url','name','position']

                      def as_json(options=nil)
                        attributes.slice(*JSON_ATTRS)
                      end

                  end




Wednesday, July 14, 2010
JSON in ActiveRecord
                  class Bookmark < ActiveRecord::Base

                      JSON_ATTRS = ['id','owner_id','owner_type','url','name','position']

                      def as_json(options=nil)
                        attributes.slice(*JSON_ATTRS)
                      end

                  end

                  class Box < ActiveRecord::Base

                      JSON_ATTRS = ['id','column_id','title','style','collapsed','position']

                      belongs_to     :column
                      has_many       :bookmarks, :as => :owner, :order => 'position'
                      acts_as_list   :scope => :column_id

                      def as_json(options=nil)
                        attributes.slice(*JSON_ATTRS).merge(:bookmarks => bookmarks)
                      end

                  end




Wednesday, July 14, 2010
JSON in ActiveRecord
        >> Bookmark.find(27726).to_json
        => "{"position 1,
                          ": "name "Prototype
                                     ":                                               class User < ActiveRecord::Base
        Framework   ", "url "http:/
                              ":       /prototypejs.org/",
        "owner_id  ":7181, ":27726,
                                "id         "owner_type":                             JSON_ATTRS = ['id','email','uuid'].freeze
        "Box "}"
                                                                                        has_one    :inbox
        >> Box.find(7181).to_json                                                       has_one    :trashbox
        => "{ "position      ":4, "title "JavaScript Refs
                                              ":                         ",            has_many   :columns, :order => 'position'
        "collapsed     ":true, ":7181,
                                     "id            "bookmarks         ":             has_many   :boxes, :through => :columns
        [{  "position 1,": "name "Prototype Framework
                                            ":                                                    :order => 'columns.position,
        
         ", "url "http:/
                 ":             /prototypejs.org/          ", "owner_id       ":
                                                                                                             boxes.position'
        7181, ":27726,
                 "id                  "owner_type "Box ":        "},
        { "position   ":2, "name "Scriptaclous
                                           ":
        Framework        ", "url "http:/
                                     ":          /script.aculo.us/         ",         def as_json(options={})
        "owner_id       ":7181, ":27725,
                                        "id             "owner_type          ":         attributes.slice(*JSON_ATTRS).merge(
        "Box "position 
                "},{                   ":3, "name "DevGuru
                                                     ":                                    :inbox => inbox,
        (JavaScript)       ", "url "http:/
                                       ":         /                                        :trashbox => trashbox,
        www.devguru.com/technologies/javascript/                                            :columns => columns
        home.asp    ", "owner_id         ":7181, ":
                                                      "id                                )
        27724,    "owner_type "Box "position
                                           ":      "},{                ":             end
        4, "name "Dean Edwards Base.js
                    ":                                     ", "url ":
        "http:/   /dean.edwards.name/weblog/                                          end
        2006/03/base/             ", "owner_id     ":7181, ":  "id
        27723,    "owner_type "Box     ":      "}], "column_id       ":
        3538,   "style "yellow_green
                            ":                      "}"




Wednesday, July 14, 2010
JSON in ActiveRecord
                 Don’t Over think!

                 There Are Tools For
                 Everything

                 Use Them




Wednesday, July 14, 2010
JSON in ActiveRecord
                 Don’t Over think!     data = "{"position":
                                       1,"name":"Prototype
                                       Framework","url":
                 There Are Tools For   "http://prototypejs.org/",
                                       "owner_id":7181,"id":
                 Everything            27726,"owner_type":"Box
                                       "}"

                 Use Them              Bookmark.new.from_json(data)
                                       # => #<Bookmark id: nil,
                                       owner_id: nil, url: "http://
                                       prototypejs.org/", name:
                                       "Prototype Framework",
                                       created_at: nil, position:
                                       0, owner_type: nil,
                                       updated_at: nil>




Wednesday, July 14, 2010
The Backend
                             ( part 2 - web app controller )




Wednesday, July 14, 2010
Changing State




Wednesday, July 14, 2010
Changing State

                                  CREATE   READ     UPDATE   DELETE

                           DB     INSERT   SELECT   UPDATE   DELETE

                           HTTP    POST     GET      PUT     DELETE




Wednesday, July 14, 2010
Changing State

                                  CREATE   READ     UPDATE   DELETE

                           DB     INSERT   SELECT   UPDATE   DELETE

                           HTTP    POST     GET      PUT     DELETE




Wednesday, July 14, 2010
Changing State

                                  CREATE   READ     UPDATE   DELETE

                           DB     INSERT   SELECT   UPDATE   DELETE

                           HTTP    POST     GET      PUT     DELETE




Wednesday, July 14, 2010
Changing State

                                   CREATE    READ     UPDATE   DELETE

                            DB     INSERT    SELECT   UPDATE   DELETE

                           HTTP     POST      GET      PUT     DELETE


                           Representational State Transfer (REST)



Wednesday, July 14, 2010
Resource
       Routes




Wednesday, July 14, 2010
Resource
       Routes              Homemarks::Application.routes.draw do |map|

                             resources :users
                             resource :session

                             resources :columns do
                               collection { put :sort }
                               member     { delete :destroy_boxes }
                             end

                             resources :boxes do
                               collection { put :sort }
                               member do
                                 put :toggle_collapse
                                 put :colorize
                                 put :change_title
                               end
                             end

                           end




Wednesday, July 14, 2010
Resource
       Routes                    Homemarks::Application.routes.draw do |map|

                                   resources :users
                                   resource :session

              1 line 7 actions     resources :columns do
                                     collection { put :sort }
                                     member     { delete :destroy_boxes }
                                   end

                                   resources :boxes do
                                     collection { put :sort }
                                     member do
                                       put :toggle_collapse
                                       put :colorize
                                       put :change_title
                                     end
                                   end

                                 end




Wednesday, July 14, 2010
Resource
       Routes                    Homemarks::Application.routes.draw do |map|

                                   resources :users
                                   resource :session

              1 line 7 actions     resources :columns do
                                     collection { put :sort }
                                     member     { delete :destroy_boxes }
              Collections &        end
              Members              resources :boxes do
                                     collection { put :sort }
                                     member do
                                       put :toggle_collapse
                                       put :colorize
                                       put :change_title
                                     end
                                   end

                                 end




Wednesday, July 14, 2010
Resource
       Routes                    Homemarks::Application.routes.draw do |map|

                                   resources :users
                                   resource :session

              1 line 7 actions     resources :columns do
                                     collection { put :sort }
                                     member     { delete :destroy_boxes }
              Collections &        end
              Members              resources :boxes do
                                     collection { put :sort }
                                     member do
              Current User             put :toggle_collapse
                                       put :colorize
              Scope Implied            put :change_title
                                     end
                                   end

                                 end




Wednesday, July 14, 2010
Resource
       Routes                    Homemarks::Application.routes.draw do |map|

                                   resources :users
                                   resource :session

              1 line 7 actions     resources :columns do
                                     collection { put :sort }
                                     member     { delete :destroy_boxes }
              Collections &        end
              Members              resources :boxes do
                                     collection { put :sort }
                                     member do
              Current User             put :toggle_collapse
                                       put :colorize
              Scope Implied            put :change_title
                                     end
                                   end
              You will PUT
                                 end




Wednesday, July 14, 2010
Generated URLs
             $ rake routes CONTROLLER=users

              GET          /users(.:format)            {:controller=>"users",   :action=>"index"}
              POST         /users(.:format)            {:controller=>"users",   :action=>"create"}
              GET          /users/new(.:format)        {:controller=>"users",   :action=>"new"}
              GET          /users/:id(.:format)        {:controller=>"users",   :action=>"show"}
              PUT          /users/:id(.:format)        {:controller=>"users",   :action=>"update"}
              DELETE       /users/:id(.:format)        {:controller=>"users",   :action=>"destroy"}
              GET          /users/:id/edit(.:format)   {:controller=>"users",   :action=>"edit"}




Wednesday, July 14, 2010
RESTful Actions
                class BoxesController < ApplicationController

                   def create
                     @box = current_user.columns.find(params[:column_id]).boxes.create!
                     render :json => @box.id
                   end

                   def sort
                     @box.insert_at params[:position] ; head :ok
                   end

                   def toggle_collapse
                     @box.toggle(:collapsed).save! ; head :ok
                   end

                end

                class SessionsController < ApplicationController

                   def create
                     self.current_user = User.authenticate params[:email], params[:password]
                     logged_in? ?
                       head(:ok) : render(:json => login_failures, :status => :unauthorized)
                   end

                end



Wednesday, July 14, 2010
Configure Mime Types
             Mime::Type.register_alias "text/html", :iphone
             Mime::Type.register_alias "text/html", :myiphoneapp_html
             Mime::Type.register_alias "application/json", :myiphoneapp_json




Wednesday, July 14, 2010
class ApplicationController < ActionController::Base




        Critical
                            protect_from_forgery
                            before_filter :set_myiphone_app_request
                            after_filter :brand_response_headers

                            protected




        Support             def myiphone_app_request?
                              request.env["HTTP_USER_AGENT"] &&

                            end
                                request.env["HTTP_USER_AGENT"][/HomeMarks iPhone/d.d/]


                            def set_myiphone_app_request
                              if myiphone_app_request?
                                case request.format.symbol
                                when :json then request.format = :myiphoneapp_json
                                when :html then request.format = :myiphoneapp_html
                                end
                              end
                            end

                            def brand_response_headers
                              response.headers['X-Homemarks'] = '3.0'
                            end

                            def set_iphone_request
                              request.format = :iphone if iphone_request?
                            end

                            def iphone_request?
                              !myiphone_app_request? &&
                                request.env["HTTP_USER_AGENT"] &&
                                request.env["HTTP_USER_AGENT"][/(iPhone|iPod)/]
                            end

                            def protect_against_forgery?
                              myiphone_app_request? ? false : super
                            end

                           end




Wednesday, July 14, 2010
The Frontend
                             ( part 1 - core data model )




Wednesday, July 14, 2010
ObjC RESTful Resource




Wednesday, July 14, 2010
ObjC RESTful Resource




Wednesday, July 14, 2010
ObjC RESTful Resource




Wednesday, July 14, 2010
ObjC RESTful Resource




Wednesday, July 14, 2010
ObjC RESTful Resource




Wednesday, July 14, 2010
ObjC RESTful Resource




                           http://code.google.com/p/json-framework/
                            http:/ /allseeing-i.com/ASIHTTPRequest/


Wednesday, July 14, 2010
MyApp Singletons
                 // Hard core singleton pattern.

                 [[UIApplication sharedApplication] openURL:...]
                 [[NSURLCredentialStorage sharedCredentialStorage] allCredentials]


                 // Simple class method singleton pattern.

                 [MyApp    mom]         //   NSManagedObjectModel
                 [MyApp    moc]         //   NSManagedObjectContext
                 [MyApp    mocImport]   //   NSManagedObjectContext
                 [MyApp    psc]         //   NSPersistentStoreCoordinator

                 [MyApp userAgent]      // NSString

                 [MyApp queue]                 // ASINetworkQueue
                 [MyApp myUrlFor:action]       // NSURL




Wednesday, July 14, 2010
Core
                           @implementation MyApp

                           + (NSManagedObjectModel *)mom {
                             static NSManagedObjectModel *mom;
                             if (mom == nil) {



       Data
                               mom = [[NSManagedObjectModel mergedModelFromBundles:nil] retain];
                             }
                             return mom;
                           }

                           + (NSManagedObjectContext *)moc {
                             static NSManagedObjectContext *moc;
                             if (moc == nil) {
                               NSPersistentStoreCoordinator *psc = [self psc];
                               if (psc != nil) {
                                 moc = [[NSManagedObjectContext alloc] init];
                                 [moc setPersistentStoreCoordinator:psc];
                                 [moc setUndoManager:nil];
                                 [moc setStalenessInterval:3.0];
                               }
                             }
                             return moc;
                           }

                           + (NSManagedObjectContext *)mocImport {
                             // Do same thing above, make sure undo mgr is nil.
                           }

                           + (NSPersistentStoreCoordinator *)psc {
                             static NSPersistentStoreCoordinator *psc;
                             if (psc == nil)
                               // Normal PSC code here.
                             return psc;
                           }

                           @end




Wednesday, July 14, 2010
#pragma mark Network

         + (ASINetworkQueue *)queue {


                                                                           Misc
           static ASINetworkQueue *queue;
           if (queue == nil) {
             queue = [[ASINetworkQueue queue] retain];
             [queue go];
           }
           return queue;
         }

         + (NSURL *)myUrlFor:(NSString *)action {
           return [NSURL URLWithString:[NSString stringWithFormat:@"http://%@/%@", [self siteHost],
                                                                                   action]];
         }

         #pragma mark Device/Bundle

         // http://www.drobnik.com/touch/2009/07/determining-the-hardware-model/

         + (NSString *)userAgent {
           static NSString *ua;
           if (ua == nil) {
             NSString *appVersion = [self appVersion];
             NSString *platformString = [[UIDevice currentDevice] platformString];
             NSString *systemVersion = [UIDevice currentDevice].systemVersion;
             ua = [[NSString stringWithFormat:@"HomeMarks iPhone/%@ (%@; %@)",
                                              appVersion,platformString,systemVersion] retain];
           }
           return ua;
         }




Wednesday, July 14, 2010
Taming Core Data




Wednesday, July 14, 2010
Taming Core Data
              Set the class for all
              your models and
              generate classes!




Wednesday, July 14, 2010
Taming Core Data
              Set the class for all
              your models and
              generate classes!

              Subclass
              NSManagedObject
              to your name space.




Wednesday, July 14, 2010
Taming Core Data
              Set the class for all
              your models and
              generate classes!

              Subclass
              NSManagedObject
              to your name space.

              Make all your
              generated model
              classes subclass
              from above.


Wednesday, July 14, 2010
Less Wizardry
            @implementation MyManagedObject

            #pragma mark Reflection

            + (NSEntityDescription *)entity {
              return [[[MyApp mom] entitiesByName] objectForKey:NSStringFromClass(self)];
            }

            + (NSFetchRequest *)fetchRequestForEntity {
              NSFetchRequest *fetchRequest = [[[NSFetchRequest alloc] init] autorelease];
              [fetchRequest setEntity:[self entity]];
              return fetchRequest;
            }

            @end




Wednesday, July 14, 2010
Less Wizardry
       @implementation MyManagedObject

       #pragma mark Finders

       + (MyManagedObject *)objectWithID:(NSString *)anId {
         if (anId == nil) return nil;
         NSURL *myURL = [NSURL URLWithString:anId];
         NSManagedObjectID *myId = [[MyApp psc] managedObjectIDForURIRepresentation:myURL];
         return (MyManagedObject *)[[MyApp moc] objectWithID:myId];
       }

       - (NSString *)objectIDURLString {
         return [[[self objectID] URIRepresentation] absoluteString];
       }

       @end




                                               x-coredata://EB8922D9- DC06-4256-A21B-DFFD47D7E6DA/MyEntity/p3

Wednesday, July 14, 2010
Create/Import Helpers
          @implementation MyManagedObject

          #pragma mark Creators

          + (id)newObject:(NSDictionary *)attributes {
            return [self newObject:attributes inContext:nil];
          }

          + (id)newObject:(NSDictionary *)attributes inContext:(NSManagedObjectContext *)context {
            NSManagedObjectContext *moc = context ? context : [MyApp moc];
            id mobj = [[self alloc] initWithEntity:[self entity] insertIntoManagedObjectContext:moc];
            if (attributes != nil) {
              for (id key in attributes) {
                [mobj setValue:[attributes valueForKey:key] forKey:key];
              }
            }
            return mobj;
          }

          @end




Wednesday, July 14, 2010
The Frontend
                              ( part 2 - external api )




Wednesday, July 14, 2010
Customize To Your API
       // Assumes MyRequest & MyFormRequest subclasses of
       // ASIHTTPRequest and ASIFormDataRequest (minimal use).

       @implementation ASIHTTPRequest (MyAdditions)

       #pragma mark Designated Initializer

       - (id)initWithMyURL:(NSURL *)newURL {
         self = [self initWithURL:newURL];
         self.username = [MyApp userEmail];
         self.password = [MyApp userPass];
         self.useCookiePersistance = NO;
         self.useSessionPersistance = NO;
         self.useKeychainPersistance = NO;
         self.allowCompressedResponse = YES;
         self.shouldRedirect = NO;
         self.requestMethod = @"GET";
         self.delegate = [MyApp appDelegate];
         self.didFinishSelector = @selector(globalRequestFinished:);
         self.didFailSelector = @selector(globalRequestFailed:);
         [self addRequestHeader:@"HTTP_ACCEPT" value:@"application/json"];
         [self addRequestHeader:@"User-Agent" value:[MyApp userAgent]];
         return self;
       }

       #pragma mark Utility

       + (NSURL *)urlFor:(NSString *)action {
         NSURL *url = [NSURL URLWithString:[NSString stringWithFormat:@"http://%@/%@",[MyApp siteHost],action]];
         return url;
       }

        + (MyRequest *)myRequestFor:(NSString *)action {
Wednesday, July 14, 2010
}

          #pragma mark Utility

          + (NSURL *)urlFor:(NSString *)action {
            NSURL *url = [NSURL URLWithString:[NSString stringWithFormat:@"http://%@/%@",[MyApp siteHost],action]];
            return url;
          }

          + (MyRequest *)myRequestFor:(NSString *)action {
            MyRequest *request = [[[MyRequest alloc] initWithMyURL:[self urlFor:action]] autorelease];
            return request;
          }

          + (MyFormRequest *)myFormRequestFor:(NSString *)action withParams:(NSDictionary *)params {
            MyFormRequest *request = [[[MyFormRequest alloc] initWithMyURL:[self urlFor:action]] autorelease];
            if (params != nil) {
              for (id key in params) {
                [request setPostValue:[params objectForKey:key] forKey:key];
              }
            }
            request.requestMethod = @"POST";
            return request;
          }

          + (MyFormRequest *)myPutRequestFor:(NSString *)action withParams:(NSDictionary *)params {
            MyFormRequest *request = [self myFormRequestFor:action withParams:params];
            request.requestMethod = @"PUT";
            return request;
          }

          + (MyRequest *)myDeleteRequestFor:(NSString *)action {
            MyRequest *request = [self myRequestFor:action];
            request.requestMethod = @"DELETE";
            return request;
          }

          @end




Wednesday, July 14, 2010
Import On Launch
                   @implementation ASIHTTPRequest (MyAdditions)

                   + (void)getUserDataFor:(id)aDelegate {
                     MyRequest *request = [self myRequestFor:@"myhome.json"];
                     request.delegate = aDelegate;
                     request.didFinishSelector = @selector(didGetUserData:);
                     request.didFailSelector = @selector(didNotGetUserData:);
                     if ([MyApp userEtag] != nil) {
                       [request addRequestHeader:@"If-None-Match" value:[MyApp userEtag]];
                     }
                     [[MyApp queue] addOperation:request];
                   }

                   @end




Wednesday, July 14, 2010
Import On Launch
                   @implementation ASIHTTPRequest (MyAdditions)

                   + (void)getUserDataFor:(id)aDelegate {
                     MyRequest *request = [self myRequestFor:@"myhome.json"];
                     request.delegate = aDelegate;
                     request.didFinishSelector = @selector(didGetUserData:);
                     request.didFailSelector = @selector(didNotGetUserData:);
                     if ([MyApp userEtag] != nil) {
                       [request addRequestHeader:@"If-None-Match" value:[MyApp userEtag]];
                     }
                     [[MyApp queue] addOperation:request];
                   }

                   @end




Wednesday, July 14, 2010
Import On Launch
                             The Controller (request delegate)
                 - (void)didGetUserData:(MyRequest *)request {
                   if ([request isNotModified]) {
                     [[MyApp appDelegate] didGetUserData];
                     return;
                   } else {
                     [MyApp setUserEtag:[[request responseHeaders] objectForKey:@"Etag"]];
                     [self importUserData:[request responseJSON]];
                     [[MyApp appDelegate] didGetUserData];
                   }
                 }




Wednesday, July 14, 2010
Import On Launch
                             The Controller (request delegate)
                 - (void)didGetUserData:(MyRequest *)request {
                   if ([request isNotModified]) {
                     [[MyApp appDelegate] didGetUserData];
                     return;
                   } else {
                     [MyApp setUserEtag:[[request responseHeaders] objectForKey:@"Etag"]];
                     [self importUserData:[request responseJSON]];
                     [[MyApp appDelegate] didGetUserData];
                   }
                 }




Wednesday, July 14, 2010
Import On Launch
                             The Controller (request delegate)
                 - (void)didGetUserData:(MyRequest *)request {
                   if ([request isNotModified]) {
                     [[MyApp appDelegate] didGetUserData];
                     return;
                   } else {
                     [MyApp setUserEtag:[[request responseHeaders] objectForKey:@"Etag"]];
                     [self importUserData:[request responseJSON]];
                     [[MyApp appDelegate] didGetUserData];
                   }
                 }




                                            Apache Logs
            "GET /myhome.json HTTP/1.1" 200 5115 "-" "MyApp iPhone/1.0 (iPhone 3GS; 3.1.3)"
            "GET /myhome.json HTTP/1.1" 304 - "-" "MyApp iPhone/1.0 (iPhone 3GS; 3.1.3)"




Wednesday, July 14, 2010
Import On Launch
                             The Controller (request delegate)
                 - (void)didGetUserData:(MyRequest *)request {
                   if ([request isNotModified]) {
                     [[MyApp appDelegate] didGetUserData];
                     return;
                   } else {
                     [MyApp setUserEtag:[[request responseHeaders] objectForKey:@"Etag"]];
                     [self importUserData:[request responseJSON]];
                     [[MyApp appDelegate] didGetUserData];
                   }
                 }




                                            Apache Logs
            "GET /myhome.json HTTP/1.1" 200 5115 "-" "MyApp iPhone/1.0 (iPhone 3GS; 3.1.3)"
            "GET /myhome.json HTTP/1.1" 304 - "-" "MyApp iPhone/1.0 (iPhone 3GS; 3.1.3)"




Wednesday, July 14, 2010
Import On Launch




Wednesday, July 14, 2010
Import On Launch
         class UsersController < ApplicationController

            def home
              if stale?(:etag => current_user)
                respond_to do |format|
                  format.html { render :layout => 'application' }
                  format.hmiphoneapp_json { render :json => current_user }
                end
              end
            end

         end




Wednesday, July 14, 2010
Import On Launch
         class UsersController < ApplicationController

            def home
              if stale?(:etag => current_user)
                respond_to do |format|
                  format.html { render :layout => 'application' }
                  format.hmiphoneapp_json { render :json => current_user }
                end
              end
            end

         end

         @implementation MyAppDelegate

         - (BOOL)application:(UIApplication *)application
                 didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
           [[NSNotificationCenter defaultCenter] addObserver:self
                                                    selector:@selector(clearEtag:)
                                                        name:NSManagedObjectContextDidSaveNotification
                                                      object:[HMApp moc]];
           //...
         }

         - (void)clearEtag:(NSNotification *)notification {
           [MyApp removeUserEtag];
         }

         @end



Wednesday, July 14, 2010
Models Drive
              @implementation MyManagedObject

              #pragma mark MyRequest Handling

              - (void)createRemoteFinished:(MyRequest *)request {
                if ([request isSuccessfulMyAppText]) {
                  NSInteger *remoteInt = [[request responseString] integerValue];
                  NSNumber *remoteId = [NSNumber numberWithInteger:remoteInt];
                  [self setValue:remoteId forKey:@"remoteId"];
                  [self save];
                }
              }

              @end




Wednesday, July 14, 2010
Models Drive
              @implementation MyManagedObject

              #pragma mark MyRequest Handling

              - (void)createRemoteFinished:(MyRequest *)request {
                if ([request isSuccessfulMyAppText]) {
                  NSInteger *remoteInt = [[request responseString] integerValue];
                  NSNumber *remoteId = [NSNumber numberWithInteger:remoteInt];
                  [self setValue:remoteId forKey:@"remoteId"];
                  [self save];
                }
              }

              @end


              @implementation HMColumn

              + (void)createRemote {
                HMColumn *newColumn = [[self class] newObject:nil];
                //...
                [newColumn save];
                [MyRequest columnCreate:newColumn];
                [newColumn release];
              }

              @end

Wednesday, July 14, 2010
@implementation HMColumn

              + (void)createRemote {
                HMColumn *newColumn = [[self class] newObject:nil];
                //...
                [newColumn save];
                [MyRequest columnCreate:newColumn];
                [newColumn release];
              }

              @end


              @implementation MyRequest

              + (void)columnCreate:(HMColumn *)column {
                MyFormRequest *request = [self myFormRequestFor:@"columns" withParams:nil];
                request.delegate = column;
                request.didFinishSelector = @selector(createRemoteFinished:);
                request.didFailSelector = @selector(createRemoteFailed:);
                [[HMApp queue] addOperation:request];
              }

              @end




Wednesday, July 14, 2010
Models Drive (box example)
         @implementation HMBox

         - (void)colorize {
           if ([[self changedValues] hasKey:@"style"] && [self save])
             [HMRequest boxColorize:self];
         }

         @end


         @implementation ASIHTTPRequest (MyAdditions)

         + (NSString *)box:(HMBox *)box action:(NSString *)action {
           return [NSString stringWithFormat:@"boxes/%@/%@",[[box remoteId] stringValue],action];
         }

         + (void)boxColorize:(HMBox *)box {
           NSString *action = [self box:box action:@"colorize"];
           NSDictionary *params = [NSDictionary dictionaryWithObjectsAndKeys:box.style,@"color",nil];
           MyFormRequest *request = [self myPutRequestFor:action withParams:params];
           [[MyApp queue] addOperation:request];
         }

         @end




Wednesday, July 14, 2010
The End
                           ( liked my talk – buy my app - write a review )




Wednesday, July 14, 2010

Contenu connexe

Similaire à Synchronizing Core Data With Rails

JSON Part 2: Working with Ajax
JSON Part 2: Working with AjaxJSON Part 2: Working with Ajax
JSON Part 2: Working with AjaxJeff Fox
 
Meteoro de pegasuus! Desenvolvendo aplicações realtime com MeteorJS
Meteoro de pegasuus! Desenvolvendo aplicações realtime com MeteorJSMeteoro de pegasuus! Desenvolvendo aplicações realtime com MeteorJS
Meteoro de pegasuus! Desenvolvendo aplicações realtime com MeteorJSJulio Antonio Mendonça de Marins
 
Krug Fat Client
Krug Fat ClientKrug Fat Client
Krug Fat ClientPaul Klipp
 
OSGi Community Event 2010 - Enterprise OSGi in WebSphere and Apache Aries
OSGi Community Event 2010 - Enterprise OSGi in WebSphere and Apache AriesOSGi Community Event 2010 - Enterprise OSGi in WebSphere and Apache Aries
OSGi Community Event 2010 - Enterprise OSGi in WebSphere and Apache Ariesmfrancis
 
Web Development with AngularJS, NodeJS and ExpressJS
Web Development with AngularJS, NodeJS and ExpressJSWeb Development with AngularJS, NodeJS and ExpressJS
Web Development with AngularJS, NodeJS and ExpressJSJoão Rocha da Silva
 
Why Nodejs Guilin Shanghai
Why Nodejs Guilin ShanghaiWhy Nodejs Guilin Shanghai
Why Nodejs Guilin ShanghaiJackson Tian
 
Why Node.js
Why Node.jsWhy Node.js
Why Node.jsguileen
 
SenchaLabs Connect & Express
SenchaLabs Connect & ExpressSenchaLabs Connect & Express
SenchaLabs Connect & ExpressTim Caswell
 
Serverside Javascript - Hope and Opportunity (Introducing Starbucks JS Web Fr...
Serverside Javascript - Hope and Opportunity (Introducing Starbucks JS Web Fr...Serverside Javascript - Hope and Opportunity (Introducing Starbucks JS Web Fr...
Serverside Javascript - Hope and Opportunity (Introducing Starbucks JS Web Fr...Mário Valente
 
ASP.NET MVC - In the Wild
ASP.NET MVC - In the WildASP.NET MVC - In the Wild
ASP.NET MVC - In the WildBrian Boatright
 
XML-Free Programming : Java Server and Client Development without &lt;>
XML-Free Programming : Java Server and Client Development without &lt;>XML-Free Programming : Java Server and Client Development without &lt;>
XML-Free Programming : Java Server and Client Development without &lt;>Arun Gupta
 
Angular jS Introduction by Google
Angular jS Introduction by GoogleAngular jS Introduction by Google
Angular jS Introduction by GoogleASG
 
Sofea and SOUI - Web future without web frameworks
Sofea and SOUI - Web future without web frameworksSofea and SOUI - Web future without web frameworks
Sofea and SOUI - Web future without web frameworksAndré Neubauer
 
Introducing React to GraysOnline
Introducing React to GraysOnlineIntroducing React to GraysOnline
Introducing React to GraysOnlineJoseph Ni
 
HTML alchemy: the secrets of mixing JavaScript and Java EE - Matthias Wessendorf
HTML alchemy: the secrets of mixing JavaScript and Java EE - Matthias WessendorfHTML alchemy: the secrets of mixing JavaScript and Java EE - Matthias Wessendorf
HTML alchemy: the secrets of mixing JavaScript and Java EE - Matthias WessendorfJAX London
 

Similaire à Synchronizing Core Data With Rails (20)

Jsp Comparison
 Jsp Comparison Jsp Comparison
Jsp Comparison
 
JSON Part 2: Working with Ajax
JSON Part 2: Working with AjaxJSON Part 2: Working with Ajax
JSON Part 2: Working with Ajax
 
Meteoro de pegasuus! Desenvolvendo aplicações realtime com MeteorJS
Meteoro de pegasuus! Desenvolvendo aplicações realtime com MeteorJSMeteoro de pegasuus! Desenvolvendo aplicações realtime com MeteorJS
Meteoro de pegasuus! Desenvolvendo aplicações realtime com MeteorJS
 
Krug Fat Client
Krug Fat ClientKrug Fat Client
Krug Fat Client
 
OSGi Community Event 2010 - Enterprise OSGi in WebSphere and Apache Aries
OSGi Community Event 2010 - Enterprise OSGi in WebSphere and Apache AriesOSGi Community Event 2010 - Enterprise OSGi in WebSphere and Apache Aries
OSGi Community Event 2010 - Enterprise OSGi in WebSphere and Apache Aries
 
Web Development with AngularJS, NodeJS and ExpressJS
Web Development with AngularJS, NodeJS and ExpressJSWeb Development with AngularJS, NodeJS and ExpressJS
Web Development with AngularJS, NodeJS and ExpressJS
 
Why Nodejs Guilin Shanghai
Why Nodejs Guilin ShanghaiWhy Nodejs Guilin Shanghai
Why Nodejs Guilin Shanghai
 
Why Node.js
Why Node.jsWhy Node.js
Why Node.js
 
SenchaLabs Connect & Express
SenchaLabs Connect & ExpressSenchaLabs Connect & Express
SenchaLabs Connect & Express
 
Node.JS briefly introduced
Node.JS briefly introducedNode.JS briefly introduced
Node.JS briefly introduced
 
Serverside Javascript - Hope and Opportunity (Introducing Starbucks JS Web Fr...
Serverside Javascript - Hope and Opportunity (Introducing Starbucks JS Web Fr...Serverside Javascript - Hope and Opportunity (Introducing Starbucks JS Web Fr...
Serverside Javascript - Hope and Opportunity (Introducing Starbucks JS Web Fr...
 
ASP.NET MVC - In the Wild
ASP.NET MVC - In the WildASP.NET MVC - In the Wild
ASP.NET MVC - In the Wild
 
XML-Free Programming : Java Server and Client Development without &lt;>
XML-Free Programming : Java Server and Client Development without &lt;>XML-Free Programming : Java Server and Client Development without &lt;>
XML-Free Programming : Java Server and Client Development without &lt;>
 
World of javascript
World of javascriptWorld of javascript
World of javascript
 
Angular jS Introduction by Google
Angular jS Introduction by GoogleAngular jS Introduction by Google
Angular jS Introduction by Google
 
Java server pages
Java server pagesJava server pages
Java server pages
 
Sofea and SOUI - Web future without web frameworks
Sofea and SOUI - Web future without web frameworksSofea and SOUI - Web future without web frameworks
Sofea and SOUI - Web future without web frameworks
 
Real-Time Web Applications with ASP.NET WebAPI and SignalR
Real-Time Web Applications with ASP.NET WebAPI and SignalRReal-Time Web Applications with ASP.NET WebAPI and SignalR
Real-Time Web Applications with ASP.NET WebAPI and SignalR
 
Introducing React to GraysOnline
Introducing React to GraysOnlineIntroducing React to GraysOnline
Introducing React to GraysOnline
 
HTML alchemy: the secrets of mixing JavaScript and Java EE - Matthias Wessendorf
HTML alchemy: the secrets of mixing JavaScript and Java EE - Matthias WessendorfHTML alchemy: the secrets of mixing JavaScript and Java EE - Matthias Wessendorf
HTML alchemy: the secrets of mixing JavaScript and Java EE - Matthias Wessendorf
 

Plus de Ken Collins

Secrets of the asset pipeline
Secrets of the asset pipelineSecrets of the asset pipeline
Secrets of the asset pipelineKen Collins
 
Dominion Enterprises _H@&lt;k@th0n_
Dominion Enterprises _H@&lt;k@th0n_Dominion Enterprises _H@&lt;k@th0n_
Dominion Enterprises _H@&lt;k@th0n_Ken Collins
 
Free The Enterprise With Ruby & Master Your Own Domain
Free The Enterprise With Ruby & Master Your Own DomainFree The Enterprise With Ruby & Master Your Own Domain
Free The Enterprise With Ruby & Master Your Own DomainKen Collins
 
Memcached Presentation @757rb
Memcached Presentation @757rbMemcached Presentation @757rb
Memcached Presentation @757rbKen Collins
 
Oo java script class construction
Oo java script class constructionOo java script class construction
Oo java script class constructionKen Collins
 

Plus de Ken Collins (7)

Secrets of the asset pipeline
Secrets of the asset pipelineSecrets of the asset pipeline
Secrets of the asset pipeline
 
Ruby struct
Ruby structRuby struct
Ruby struct
 
Dominion Enterprises _H@&lt;k@th0n_
Dominion Enterprises _H@&lt;k@th0n_Dominion Enterprises _H@&lt;k@th0n_
Dominion Enterprises _H@&lt;k@th0n_
 
Free The Enterprise With Ruby & Master Your Own Domain
Free The Enterprise With Ruby & Master Your Own DomainFree The Enterprise With Ruby & Master Your Own Domain
Free The Enterprise With Ruby & Master Your Own Domain
 
Memcached Presentation @757rb
Memcached Presentation @757rbMemcached Presentation @757rb
Memcached Presentation @757rb
 
Oo java script class construction
Oo java script class constructionOo java script class construction
Oo java script class construction
 
Tool Time
Tool TimeTool Time
Tool Time
 

Dernier

Slack Application Development 101 Slides
Slack Application Development 101 SlidesSlack Application Development 101 Slides
Slack Application Development 101 Slidespraypatel2
 
How to Troubleshoot Apps for the Modern Connected Worker
How to Troubleshoot Apps for the Modern Connected WorkerHow to Troubleshoot Apps for the Modern Connected Worker
How to Troubleshoot Apps for the Modern Connected WorkerThousandEyes
 
Unblocking The Main Thread Solving ANRs and Frozen Frames
Unblocking The Main Thread Solving ANRs and Frozen FramesUnblocking The Main Thread Solving ANRs and Frozen Frames
Unblocking The Main Thread Solving ANRs and Frozen FramesSinan KOZAK
 
How to Remove Document Management Hurdles with X-Docs?
How to Remove Document Management Hurdles with X-Docs?How to Remove Document Management Hurdles with X-Docs?
How to Remove Document Management Hurdles with X-Docs?XfilesPro
 
Handwritten Text Recognition for manuscripts and early printed texts
Handwritten Text Recognition for manuscripts and early printed textsHandwritten Text Recognition for manuscripts and early printed texts
Handwritten Text Recognition for manuscripts and early printed textsMaria Levchenko
 
Injustice - Developers Among Us (SciFiDevCon 2024)
Injustice - Developers Among Us (SciFiDevCon 2024)Injustice - Developers Among Us (SciFiDevCon 2024)
Injustice - Developers Among Us (SciFiDevCon 2024)Allon Mureinik
 
[2024]Digital Global Overview Report 2024 Meltwater.pdf
[2024]Digital Global Overview Report 2024 Meltwater.pdf[2024]Digital Global Overview Report 2024 Meltwater.pdf
[2024]Digital Global Overview Report 2024 Meltwater.pdfhans926745
 
Install Stable Diffusion in windows machine
Install Stable Diffusion in windows machineInstall Stable Diffusion in windows machine
Install Stable Diffusion in windows machinePadma Pradeep
 
The Codex of Business Writing Software for Real-World Solutions 2.pptx
The Codex of Business Writing Software for Real-World Solutions 2.pptxThe Codex of Business Writing Software for Real-World Solutions 2.pptx
The Codex of Business Writing Software for Real-World Solutions 2.pptxMalak Abu Hammad
 
Key Features Of Token Development (1).pptx
Key  Features Of Token  Development (1).pptxKey  Features Of Token  Development (1).pptx
Key Features Of Token Development (1).pptxLBM Solutions
 
The 7 Things I Know About Cyber Security After 25 Years | April 2024
The 7 Things I Know About Cyber Security After 25 Years | April 2024The 7 Things I Know About Cyber Security After 25 Years | April 2024
The 7 Things I Know About Cyber Security After 25 Years | April 2024Rafal Los
 
Tech-Forward - Achieving Business Readiness For Copilot in Microsoft 365
Tech-Forward - Achieving Business Readiness For Copilot in Microsoft 365Tech-Forward - Achieving Business Readiness For Copilot in Microsoft 365
Tech-Forward - Achieving Business Readiness For Copilot in Microsoft 3652toLead Limited
 
Breaking the Kubernetes Kill Chain: Host Path Mount
Breaking the Kubernetes Kill Chain: Host Path MountBreaking the Kubernetes Kill Chain: Host Path Mount
Breaking the Kubernetes Kill Chain: Host Path MountPuma Security, LLC
 
#StandardsGoals for 2024: What’s new for BISAC - Tech Forum 2024
#StandardsGoals for 2024: What’s new for BISAC - Tech Forum 2024#StandardsGoals for 2024: What’s new for BISAC - Tech Forum 2024
#StandardsGoals for 2024: What’s new for BISAC - Tech Forum 2024BookNet Canada
 
Scaling API-first – The story of a global engineering organization
Scaling API-first – The story of a global engineering organizationScaling API-first – The story of a global engineering organization
Scaling API-first – The story of a global engineering organizationRadu Cotescu
 
04-2024-HHUG-Sales-and-Marketing-Alignment.pptx
04-2024-HHUG-Sales-and-Marketing-Alignment.pptx04-2024-HHUG-Sales-and-Marketing-Alignment.pptx
04-2024-HHUG-Sales-and-Marketing-Alignment.pptxHampshireHUG
 
Human Factors of XR: Using Human Factors to Design XR Systems
Human Factors of XR: Using Human Factors to Design XR SystemsHuman Factors of XR: Using Human Factors to Design XR Systems
Human Factors of XR: Using Human Factors to Design XR SystemsMark Billinghurst
 
Enhancing Worker Digital Experience: A Hands-on Workshop for Partners
Enhancing Worker Digital Experience: A Hands-on Workshop for PartnersEnhancing Worker Digital Experience: A Hands-on Workshop for Partners
Enhancing Worker Digital Experience: A Hands-on Workshop for PartnersThousandEyes
 
Pigging Solutions Piggable Sweeping Elbows
Pigging Solutions Piggable Sweeping ElbowsPigging Solutions Piggable Sweeping Elbows
Pigging Solutions Piggable Sweeping ElbowsPigging Solutions
 
WhatsApp 9892124323 ✓Call Girls In Kalyan ( Mumbai ) secure service
WhatsApp 9892124323 ✓Call Girls In Kalyan ( Mumbai ) secure serviceWhatsApp 9892124323 ✓Call Girls In Kalyan ( Mumbai ) secure service
WhatsApp 9892124323 ✓Call Girls In Kalyan ( Mumbai ) secure servicePooja Nehwal
 

Dernier (20)

Slack Application Development 101 Slides
Slack Application Development 101 SlidesSlack Application Development 101 Slides
Slack Application Development 101 Slides
 
How to Troubleshoot Apps for the Modern Connected Worker
How to Troubleshoot Apps for the Modern Connected WorkerHow to Troubleshoot Apps for the Modern Connected Worker
How to Troubleshoot Apps for the Modern Connected Worker
 
Unblocking The Main Thread Solving ANRs and Frozen Frames
Unblocking The Main Thread Solving ANRs and Frozen FramesUnblocking The Main Thread Solving ANRs and Frozen Frames
Unblocking The Main Thread Solving ANRs and Frozen Frames
 
How to Remove Document Management Hurdles with X-Docs?
How to Remove Document Management Hurdles with X-Docs?How to Remove Document Management Hurdles with X-Docs?
How to Remove Document Management Hurdles with X-Docs?
 
Handwritten Text Recognition for manuscripts and early printed texts
Handwritten Text Recognition for manuscripts and early printed textsHandwritten Text Recognition for manuscripts and early printed texts
Handwritten Text Recognition for manuscripts and early printed texts
 
Injustice - Developers Among Us (SciFiDevCon 2024)
Injustice - Developers Among Us (SciFiDevCon 2024)Injustice - Developers Among Us (SciFiDevCon 2024)
Injustice - Developers Among Us (SciFiDevCon 2024)
 
[2024]Digital Global Overview Report 2024 Meltwater.pdf
[2024]Digital Global Overview Report 2024 Meltwater.pdf[2024]Digital Global Overview Report 2024 Meltwater.pdf
[2024]Digital Global Overview Report 2024 Meltwater.pdf
 
Install Stable Diffusion in windows machine
Install Stable Diffusion in windows machineInstall Stable Diffusion in windows machine
Install Stable Diffusion in windows machine
 
The Codex of Business Writing Software for Real-World Solutions 2.pptx
The Codex of Business Writing Software for Real-World Solutions 2.pptxThe Codex of Business Writing Software for Real-World Solutions 2.pptx
The Codex of Business Writing Software for Real-World Solutions 2.pptx
 
Key Features Of Token Development (1).pptx
Key  Features Of Token  Development (1).pptxKey  Features Of Token  Development (1).pptx
Key Features Of Token Development (1).pptx
 
The 7 Things I Know About Cyber Security After 25 Years | April 2024
The 7 Things I Know About Cyber Security After 25 Years | April 2024The 7 Things I Know About Cyber Security After 25 Years | April 2024
The 7 Things I Know About Cyber Security After 25 Years | April 2024
 
Tech-Forward - Achieving Business Readiness For Copilot in Microsoft 365
Tech-Forward - Achieving Business Readiness For Copilot in Microsoft 365Tech-Forward - Achieving Business Readiness For Copilot in Microsoft 365
Tech-Forward - Achieving Business Readiness For Copilot in Microsoft 365
 
Breaking the Kubernetes Kill Chain: Host Path Mount
Breaking the Kubernetes Kill Chain: Host Path MountBreaking the Kubernetes Kill Chain: Host Path Mount
Breaking the Kubernetes Kill Chain: Host Path Mount
 
#StandardsGoals for 2024: What’s new for BISAC - Tech Forum 2024
#StandardsGoals for 2024: What’s new for BISAC - Tech Forum 2024#StandardsGoals for 2024: What’s new for BISAC - Tech Forum 2024
#StandardsGoals for 2024: What’s new for BISAC - Tech Forum 2024
 
Scaling API-first – The story of a global engineering organization
Scaling API-first – The story of a global engineering organizationScaling API-first – The story of a global engineering organization
Scaling API-first – The story of a global engineering organization
 
04-2024-HHUG-Sales-and-Marketing-Alignment.pptx
04-2024-HHUG-Sales-and-Marketing-Alignment.pptx04-2024-HHUG-Sales-and-Marketing-Alignment.pptx
04-2024-HHUG-Sales-and-Marketing-Alignment.pptx
 
Human Factors of XR: Using Human Factors to Design XR Systems
Human Factors of XR: Using Human Factors to Design XR SystemsHuman Factors of XR: Using Human Factors to Design XR Systems
Human Factors of XR: Using Human Factors to Design XR Systems
 
Enhancing Worker Digital Experience: A Hands-on Workshop for Partners
Enhancing Worker Digital Experience: A Hands-on Workshop for PartnersEnhancing Worker Digital Experience: A Hands-on Workshop for Partners
Enhancing Worker Digital Experience: A Hands-on Workshop for Partners
 
Pigging Solutions Piggable Sweeping Elbows
Pigging Solutions Piggable Sweeping ElbowsPigging Solutions Piggable Sweeping Elbows
Pigging Solutions Piggable Sweeping Elbows
 
WhatsApp 9892124323 ✓Call Girls In Kalyan ( Mumbai ) secure service
WhatsApp 9892124323 ✓Call Girls In Kalyan ( Mumbai ) secure serviceWhatsApp 9892124323 ✓Call Girls In Kalyan ( Mumbai ) secure service
WhatsApp 9892124323 ✓Call Girls In Kalyan ( Mumbai ) secure service
 

Synchronizing Core Data With Rails

  • 1. Synchronizing Core Data With Rails Ken Collins metaskills.net Wednesday, July 14, 2010
  • 4. Why Write Web Applications For The Web Only? Wednesday, July 14, 2010
  • 5. Why Write Web Applications For The Web <html> Only? Wednesday, July 14, 2010
  • 6. Why Write Web Applications For The Web <html> Only? THE BACK-END (server) Rails Web Application Wednesday, July 14, 2010
  • 7. Why Write Web Applications For The Web <html> Only? THE BACK-END (server) THE FRONT-END (clients) Rails Web Application Browser - JavaScript iPhone - Objective-C Wednesday, July 14, 2010
  • 8. Why Write Web Applications For The Web <html> Only? THE BACK-END (server) THE FRONT-END (clients) Rails Web Application Browser - JavaScript iPhone - Objective-C Wednesday, July 14, 2010
  • 9. The "AJAX Head" Design Pattern Wednesday, July 14, 2010
  • 10. The "AJAX Head" Design Pattern Wednesday, July 14, 2010
  • 11. The "AJAX Head" Design Pattern “e AJAX head design pattern forces the view and controller to work in isolation with the most minimal coupling possible. Kind of like a web service.” “...an implementation pattern that drastically modi es common web client-server interactions in order to bring them more closely in line with enterprise client-server interactions...” Wednesday, July 14, 2010
  • 12. The "AJAX Head" Design Pattern “e AJAX head design pattern forces the view and controller to work in isolation with the most minimal coupling possible. Kind of like a web service.” “...an implementation pattern that drastically modi es common web client-server interactions in order to bring them more closely in line with enterprise client-server interactions...” http://voodootikigod.com/ajax-head-design-pattern http://metaskills.net/2008/5/24/the-ajax-head-br-design-pattern http://metaskills.net/2008/6/18/restful-ajax-with-forgery-protection Wednesday, July 14, 2010
  • 13. Why Write Web Applications For The Web <html> Only? THE BACK-END (server) THE FRONT-END (clients) Rails Web Application Browser - JavaScript iPhone - Objective-C Wednesday, July 14, 2010
  • 14. Why Write Web Applications For The Web <html> Only? THE BACK-END (server) THE FRONT-END (clients) Rails Web Application Browser - JavaScript iPhone - Objective-C 1) AR Model 2) Controller Wednesday, July 14, 2010
  • 15. Why Write Web Applications For The Web <html> Only? THE BACK-END (server) THE FRONT-END (clients) Rails Web Application Browser - JavaScript iPhone - Objective-C 1) AR Model 1) CoreData Models 2) Controller 2) External API Wednesday, July 14, 2010
  • 16. The Backend ( part 1 - web app model ) Wednesday, July 14, 2010
  • 18. .0.b e t a4 3.0 Wednesday, July 14, 2010
  • 19. .0.b e t a4 3.0 Wednesday, July 14, 2010
  • 20. .0.b e t a4 3.0 Wednesday, July 14, 2010
  • 22. Data-Interchange... JSON JSON (JavaScript Object Notation) is a lightweight format. It is easy for humans to read and write. It is easy for machines to parse and generate. JSON is a text format that is completely language independent but uses conventions that are familiar to programmers of the C-family of languages, including C, C++, C#, Java, JavaScript, Perl, Python, and many others. Wednesday, July 14, 2010
  • 23. Data-Interchange... JSON JSON (JavaScript Object Notation) is a lightweight format. It is easy for humans to read and write. It is easy for machines to parse and generate. JSON is a text format that is completely language independent but uses conventions that are familiar to programmers of the C-family of languages, including C, C++, C#, Java, JavaScript, Perl, Python, and many others. http://www.json.org/ Wednesday, July 14, 2010
  • 24. JSON in Ruby/Rails class Object def to_json(options = nil) ActiveSupport::JSON.encode( self,options) end def as_json(options = nil) instance_values end end class Foo attr_accessor :bar end f = Foo.new f.bar = 'batz' puts f.to_json # => {"bar":"batz"} Wednesday, July 14, 2010
  • 25. JSON in Ruby/Rails Specifically in ActiveSupport require 'active_support/json' class Object def to_json(options = nil) ActiveSupport::JSON.encode( self,options) end def as_json(options = nil) instance_values end end class Foo attr_accessor :bar end f = Foo.new f.bar = 'batz' puts f.to_json # => {"bar":"batz"} Wednesday, July 14, 2010
  • 26. JSON in Ruby/Rails Specifically in ActiveSupport require 'active_support/json' class Object def to_json(options = nil) Object#to_json calls #as_json to ActiveSupport::JSON.encode( coerce itself into something natively self,options) encodable like Hash, Integer, or String. end Override #as_json instead of #to_json def as_json(options = nil) so you're JSON library agnostic. instance_values end end class Foo attr_accessor :bar end f = Foo.new f.bar = 'batz' puts f.to_json # => {"bar":"batz"} Wednesday, July 14, 2010
  • 27. JSON in Ruby/Rails Specifically in ActiveSupport require 'active_support/json' class Object def to_json(options = nil) Object#to_json calls #as_json to ActiveSupport::JSON.encode( coerce itself into something natively self,options) encodable like Hash, Integer, or String. end Override #as_json instead of #to_json def as_json(options = nil) so you're JSON library agnostic. instance_values end ActiveSupport::JSON does all the work end of defining #as_json on all core ruby objects. It also abstracts out decoding class Foo with hot swappable backends using attr_accessor :bar ActiveSupport::JSON.backend = end JSONGem'. ' f = Foo.new f.bar = 'batz' puts f.to_json # => {"bar":"batz"} Wednesday, July 14, 2010
  • 28. JSON in Ruby/Rails Specifically in ActiveSupport require 'active_support/json' class Object def to_json(options = nil) Object#to_json calls #as_json to ActiveSupport::JSON.encode( coerce itself into something natively self,options) encodable like Hash, Integer, or String. end Override #as_json instead of #to_json def as_json(options = nil) so you're JSON library agnostic. instance_values end ActiveSupport::JSON does all the work end of defining #as_json on all core ruby objects. It also abstracts out decoding class Foo with hot swappable backends using attr_accessor :bar ActiveSupport::JSON.backend = end JSONGem'. ' f = Foo.new In rails, with ActiveSupport, primitive f.bar = 'batz' ruby objects serialize their instance puts f.to_json # => {"bar":"batz"} variables using another core extension Object#instance_values which returns a Hash of said ivars. Wednesday, July 14, 2010
  • 29. JSON in ActiveRecord class Bookmark < ActiveRecord::Base JSON_ATTRS = ['id','owner_id','owner_type','url','name','position'] def as_json(options=nil) attributes.slice(*JSON_ATTRS) end end Wednesday, July 14, 2010
  • 30. JSON in ActiveRecord class Bookmark < ActiveRecord::Base JSON_ATTRS = ['id','owner_id','owner_type','url','name','position'] def as_json(options=nil) attributes.slice(*JSON_ATTRS) end end class Box < ActiveRecord::Base JSON_ATTRS = ['id','column_id','title','style','collapsed','position'] belongs_to :column has_many :bookmarks, :as => :owner, :order => 'position' acts_as_list :scope => :column_id def as_json(options=nil) attributes.slice(*JSON_ATTRS).merge(:bookmarks => bookmarks) end end Wednesday, July 14, 2010
  • 31. JSON in ActiveRecord >> Bookmark.find(27726).to_json => "{"position 1, ": "name "Prototype ": class User < ActiveRecord::Base Framework ", "url "http:/ ": /prototypejs.org/", "owner_id ":7181, ":27726, "id "owner_type": JSON_ATTRS = ['id','email','uuid'].freeze "Box "}" has_one :inbox >> Box.find(7181).to_json has_one :trashbox => "{ "position ":4, "title "JavaScript Refs ": ", has_many :columns, :order => 'position' "collapsed ":true, ":7181, "id "bookmarks ": has_many :boxes, :through => :columns [{ "position 1,": "name "Prototype Framework ": :order => 'columns.position, ", "url "http:/ ": /prototypejs.org/ ", "owner_id ": boxes.position' 7181, ":27726, "id "owner_type "Box ": "}, { "position ":2, "name "Scriptaclous ": Framework ", "url "http:/ ": /script.aculo.us/ ", def as_json(options={}) "owner_id ":7181, ":27725, "id "owner_type ": attributes.slice(*JSON_ATTRS).merge( "Box "position "},{ ":3, "name "DevGuru ": :inbox => inbox, (JavaScript) ", "url "http:/ ": / :trashbox => trashbox, www.devguru.com/technologies/javascript/ :columns => columns home.asp ", "owner_id ":7181, ": "id ) 27724, "owner_type "Box "position ": "},{ ": end 4, "name "Dean Edwards Base.js ": ", "url ": "http:/ /dean.edwards.name/weblog/ end 2006/03/base/ ", "owner_id ":7181, ": "id 27723, "owner_type "Box ": "}], "column_id ": 3538, "style "yellow_green ": "}" Wednesday, July 14, 2010
  • 32. JSON in ActiveRecord Don’t Over think! There Are Tools For Everything Use Them Wednesday, July 14, 2010
  • 33. JSON in ActiveRecord Don’t Over think! data = "{"position": 1,"name":"Prototype Framework","url": There Are Tools For "http://prototypejs.org/", "owner_id":7181,"id": Everything 27726,"owner_type":"Box "}" Use Them Bookmark.new.from_json(data) # => #<Bookmark id: nil, owner_id: nil, url: "http:// prototypejs.org/", name: "Prototype Framework", created_at: nil, position: 0, owner_type: nil, updated_at: nil> Wednesday, July 14, 2010
  • 34. The Backend ( part 2 - web app controller ) Wednesday, July 14, 2010
  • 36. Changing State CREATE READ UPDATE DELETE DB INSERT SELECT UPDATE DELETE HTTP POST GET PUT DELETE Wednesday, July 14, 2010
  • 37. Changing State CREATE READ UPDATE DELETE DB INSERT SELECT UPDATE DELETE HTTP POST GET PUT DELETE Wednesday, July 14, 2010
  • 38. Changing State CREATE READ UPDATE DELETE DB INSERT SELECT UPDATE DELETE HTTP POST GET PUT DELETE Wednesday, July 14, 2010
  • 39. Changing State CREATE READ UPDATE DELETE DB INSERT SELECT UPDATE DELETE HTTP POST GET PUT DELETE Representational State Transfer (REST) Wednesday, July 14, 2010
  • 40. Resource Routes Wednesday, July 14, 2010
  • 41. Resource Routes Homemarks::Application.routes.draw do |map| resources :users resource :session resources :columns do collection { put :sort } member { delete :destroy_boxes } end resources :boxes do collection { put :sort } member do put :toggle_collapse put :colorize put :change_title end end end Wednesday, July 14, 2010
  • 42. Resource Routes Homemarks::Application.routes.draw do |map| resources :users resource :session 1 line 7 actions resources :columns do collection { put :sort } member { delete :destroy_boxes } end resources :boxes do collection { put :sort } member do put :toggle_collapse put :colorize put :change_title end end end Wednesday, July 14, 2010
  • 43. Resource Routes Homemarks::Application.routes.draw do |map| resources :users resource :session 1 line 7 actions resources :columns do collection { put :sort } member { delete :destroy_boxes } Collections & end Members resources :boxes do collection { put :sort } member do put :toggle_collapse put :colorize put :change_title end end end Wednesday, July 14, 2010
  • 44. Resource Routes Homemarks::Application.routes.draw do |map| resources :users resource :session 1 line 7 actions resources :columns do collection { put :sort } member { delete :destroy_boxes } Collections & end Members resources :boxes do collection { put :sort } member do Current User put :toggle_collapse put :colorize Scope Implied put :change_title end end end Wednesday, July 14, 2010
  • 45. Resource Routes Homemarks::Application.routes.draw do |map| resources :users resource :session 1 line 7 actions resources :columns do collection { put :sort } member { delete :destroy_boxes } Collections & end Members resources :boxes do collection { put :sort } member do Current User put :toggle_collapse put :colorize Scope Implied put :change_title end end You will PUT end Wednesday, July 14, 2010
  • 46. Generated URLs $ rake routes CONTROLLER=users GET /users(.:format) {:controller=>"users", :action=>"index"} POST /users(.:format) {:controller=>"users", :action=>"create"} GET /users/new(.:format) {:controller=>"users", :action=>"new"} GET /users/:id(.:format) {:controller=>"users", :action=>"show"} PUT /users/:id(.:format) {:controller=>"users", :action=>"update"} DELETE /users/:id(.:format) {:controller=>"users", :action=>"destroy"} GET /users/:id/edit(.:format) {:controller=>"users", :action=>"edit"} Wednesday, July 14, 2010
  • 47. RESTful Actions class BoxesController < ApplicationController def create @box = current_user.columns.find(params[:column_id]).boxes.create! render :json => @box.id end def sort @box.insert_at params[:position] ; head :ok end def toggle_collapse @box.toggle(:collapsed).save! ; head :ok end end class SessionsController < ApplicationController def create self.current_user = User.authenticate params[:email], params[:password] logged_in? ? head(:ok) : render(:json => login_failures, :status => :unauthorized) end end Wednesday, July 14, 2010
  • 48. Configure Mime Types Mime::Type.register_alias "text/html", :iphone Mime::Type.register_alias "text/html", :myiphoneapp_html Mime::Type.register_alias "application/json", :myiphoneapp_json Wednesday, July 14, 2010
  • 49. class ApplicationController < ActionController::Base Critical protect_from_forgery before_filter :set_myiphone_app_request after_filter :brand_response_headers protected Support def myiphone_app_request? request.env["HTTP_USER_AGENT"] && end request.env["HTTP_USER_AGENT"][/HomeMarks iPhone/d.d/] def set_myiphone_app_request if myiphone_app_request? case request.format.symbol when :json then request.format = :myiphoneapp_json when :html then request.format = :myiphoneapp_html end end end def brand_response_headers response.headers['X-Homemarks'] = '3.0' end def set_iphone_request request.format = :iphone if iphone_request? end def iphone_request? !myiphone_app_request? && request.env["HTTP_USER_AGENT"] && request.env["HTTP_USER_AGENT"][/(iPhone|iPod)/] end def protect_against_forgery? myiphone_app_request? ? false : super end end Wednesday, July 14, 2010
  • 50. The Frontend ( part 1 - core data model ) Wednesday, July 14, 2010
  • 56. ObjC RESTful Resource http://code.google.com/p/json-framework/ http:/ /allseeing-i.com/ASIHTTPRequest/ Wednesday, July 14, 2010
  • 57. MyApp Singletons // Hard core singleton pattern. [[UIApplication sharedApplication] openURL:...] [[NSURLCredentialStorage sharedCredentialStorage] allCredentials] // Simple class method singleton pattern. [MyApp mom] // NSManagedObjectModel [MyApp moc] // NSManagedObjectContext [MyApp mocImport] // NSManagedObjectContext [MyApp psc] // NSPersistentStoreCoordinator [MyApp userAgent] // NSString [MyApp queue] // ASINetworkQueue [MyApp myUrlFor:action] // NSURL Wednesday, July 14, 2010
  • 58. Core @implementation MyApp + (NSManagedObjectModel *)mom { static NSManagedObjectModel *mom; if (mom == nil) { Data mom = [[NSManagedObjectModel mergedModelFromBundles:nil] retain]; } return mom; } + (NSManagedObjectContext *)moc { static NSManagedObjectContext *moc; if (moc == nil) { NSPersistentStoreCoordinator *psc = [self psc]; if (psc != nil) { moc = [[NSManagedObjectContext alloc] init]; [moc setPersistentStoreCoordinator:psc]; [moc setUndoManager:nil]; [moc setStalenessInterval:3.0]; } } return moc; } + (NSManagedObjectContext *)mocImport { // Do same thing above, make sure undo mgr is nil. } + (NSPersistentStoreCoordinator *)psc { static NSPersistentStoreCoordinator *psc; if (psc == nil) // Normal PSC code here. return psc; } @end Wednesday, July 14, 2010
  • 59. #pragma mark Network + (ASINetworkQueue *)queue { Misc static ASINetworkQueue *queue; if (queue == nil) { queue = [[ASINetworkQueue queue] retain]; [queue go]; } return queue; } + (NSURL *)myUrlFor:(NSString *)action { return [NSURL URLWithString:[NSString stringWithFormat:@"http://%@/%@", [self siteHost], action]]; } #pragma mark Device/Bundle // http://www.drobnik.com/touch/2009/07/determining-the-hardware-model/ + (NSString *)userAgent { static NSString *ua; if (ua == nil) { NSString *appVersion = [self appVersion]; NSString *platformString = [[UIDevice currentDevice] platformString]; NSString *systemVersion = [UIDevice currentDevice].systemVersion; ua = [[NSString stringWithFormat:@"HomeMarks iPhone/%@ (%@; %@)", appVersion,platformString,systemVersion] retain]; } return ua; } Wednesday, July 14, 2010
  • 61. Taming Core Data Set the class for all your models and generate classes! Wednesday, July 14, 2010
  • 62. Taming Core Data Set the class for all your models and generate classes! Subclass NSManagedObject to your name space. Wednesday, July 14, 2010
  • 63. Taming Core Data Set the class for all your models and generate classes! Subclass NSManagedObject to your name space. Make all your generated model classes subclass from above. Wednesday, July 14, 2010
  • 64. Less Wizardry @implementation MyManagedObject #pragma mark Reflection + (NSEntityDescription *)entity { return [[[MyApp mom] entitiesByName] objectForKey:NSStringFromClass(self)]; } + (NSFetchRequest *)fetchRequestForEntity { NSFetchRequest *fetchRequest = [[[NSFetchRequest alloc] init] autorelease]; [fetchRequest setEntity:[self entity]]; return fetchRequest; } @end Wednesday, July 14, 2010
  • 65. Less Wizardry @implementation MyManagedObject #pragma mark Finders + (MyManagedObject *)objectWithID:(NSString *)anId { if (anId == nil) return nil; NSURL *myURL = [NSURL URLWithString:anId]; NSManagedObjectID *myId = [[MyApp psc] managedObjectIDForURIRepresentation:myURL]; return (MyManagedObject *)[[MyApp moc] objectWithID:myId]; } - (NSString *)objectIDURLString { return [[[self objectID] URIRepresentation] absoluteString]; } @end x-coredata://EB8922D9- DC06-4256-A21B-DFFD47D7E6DA/MyEntity/p3 Wednesday, July 14, 2010
  • 66. Create/Import Helpers @implementation MyManagedObject #pragma mark Creators + (id)newObject:(NSDictionary *)attributes { return [self newObject:attributes inContext:nil]; } + (id)newObject:(NSDictionary *)attributes inContext:(NSManagedObjectContext *)context { NSManagedObjectContext *moc = context ? context : [MyApp moc]; id mobj = [[self alloc] initWithEntity:[self entity] insertIntoManagedObjectContext:moc]; if (attributes != nil) { for (id key in attributes) { [mobj setValue:[attributes valueForKey:key] forKey:key]; } } return mobj; } @end Wednesday, July 14, 2010
  • 67. The Frontend ( part 2 - external api ) Wednesday, July 14, 2010
  • 68. Customize To Your API // Assumes MyRequest & MyFormRequest subclasses of // ASIHTTPRequest and ASIFormDataRequest (minimal use). @implementation ASIHTTPRequest (MyAdditions) #pragma mark Designated Initializer - (id)initWithMyURL:(NSURL *)newURL { self = [self initWithURL:newURL]; self.username = [MyApp userEmail]; self.password = [MyApp userPass]; self.useCookiePersistance = NO; self.useSessionPersistance = NO; self.useKeychainPersistance = NO; self.allowCompressedResponse = YES; self.shouldRedirect = NO; self.requestMethod = @"GET"; self.delegate = [MyApp appDelegate]; self.didFinishSelector = @selector(globalRequestFinished:); self.didFailSelector = @selector(globalRequestFailed:); [self addRequestHeader:@"HTTP_ACCEPT" value:@"application/json"]; [self addRequestHeader:@"User-Agent" value:[MyApp userAgent]]; return self; } #pragma mark Utility + (NSURL *)urlFor:(NSString *)action { NSURL *url = [NSURL URLWithString:[NSString stringWithFormat:@"http://%@/%@",[MyApp siteHost],action]]; return url; } + (MyRequest *)myRequestFor:(NSString *)action { Wednesday, July 14, 2010
  • 69. } #pragma mark Utility + (NSURL *)urlFor:(NSString *)action { NSURL *url = [NSURL URLWithString:[NSString stringWithFormat:@"http://%@/%@",[MyApp siteHost],action]]; return url; } + (MyRequest *)myRequestFor:(NSString *)action { MyRequest *request = [[[MyRequest alloc] initWithMyURL:[self urlFor:action]] autorelease]; return request; } + (MyFormRequest *)myFormRequestFor:(NSString *)action withParams:(NSDictionary *)params { MyFormRequest *request = [[[MyFormRequest alloc] initWithMyURL:[self urlFor:action]] autorelease]; if (params != nil) { for (id key in params) { [request setPostValue:[params objectForKey:key] forKey:key]; } } request.requestMethod = @"POST"; return request; } + (MyFormRequest *)myPutRequestFor:(NSString *)action withParams:(NSDictionary *)params { MyFormRequest *request = [self myFormRequestFor:action withParams:params]; request.requestMethod = @"PUT"; return request; } + (MyRequest *)myDeleteRequestFor:(NSString *)action { MyRequest *request = [self myRequestFor:action]; request.requestMethod = @"DELETE"; return request; } @end Wednesday, July 14, 2010
  • 70. Import On Launch @implementation ASIHTTPRequest (MyAdditions) + (void)getUserDataFor:(id)aDelegate { MyRequest *request = [self myRequestFor:@"myhome.json"]; request.delegate = aDelegate; request.didFinishSelector = @selector(didGetUserData:); request.didFailSelector = @selector(didNotGetUserData:); if ([MyApp userEtag] != nil) { [request addRequestHeader:@"If-None-Match" value:[MyApp userEtag]]; } [[MyApp queue] addOperation:request]; } @end Wednesday, July 14, 2010
  • 71. Import On Launch @implementation ASIHTTPRequest (MyAdditions) + (void)getUserDataFor:(id)aDelegate { MyRequest *request = [self myRequestFor:@"myhome.json"]; request.delegate = aDelegate; request.didFinishSelector = @selector(didGetUserData:); request.didFailSelector = @selector(didNotGetUserData:); if ([MyApp userEtag] != nil) { [request addRequestHeader:@"If-None-Match" value:[MyApp userEtag]]; } [[MyApp queue] addOperation:request]; } @end Wednesday, July 14, 2010
  • 72. Import On Launch The Controller (request delegate) - (void)didGetUserData:(MyRequest *)request { if ([request isNotModified]) { [[MyApp appDelegate] didGetUserData]; return; } else { [MyApp setUserEtag:[[request responseHeaders] objectForKey:@"Etag"]]; [self importUserData:[request responseJSON]]; [[MyApp appDelegate] didGetUserData]; } } Wednesday, July 14, 2010
  • 73. Import On Launch The Controller (request delegate) - (void)didGetUserData:(MyRequest *)request { if ([request isNotModified]) { [[MyApp appDelegate] didGetUserData]; return; } else { [MyApp setUserEtag:[[request responseHeaders] objectForKey:@"Etag"]]; [self importUserData:[request responseJSON]]; [[MyApp appDelegate] didGetUserData]; } } Wednesday, July 14, 2010
  • 74. Import On Launch The Controller (request delegate) - (void)didGetUserData:(MyRequest *)request { if ([request isNotModified]) { [[MyApp appDelegate] didGetUserData]; return; } else { [MyApp setUserEtag:[[request responseHeaders] objectForKey:@"Etag"]]; [self importUserData:[request responseJSON]]; [[MyApp appDelegate] didGetUserData]; } } Apache Logs "GET /myhome.json HTTP/1.1" 200 5115 "-" "MyApp iPhone/1.0 (iPhone 3GS; 3.1.3)" "GET /myhome.json HTTP/1.1" 304 - "-" "MyApp iPhone/1.0 (iPhone 3GS; 3.1.3)" Wednesday, July 14, 2010
  • 75. Import On Launch The Controller (request delegate) - (void)didGetUserData:(MyRequest *)request { if ([request isNotModified]) { [[MyApp appDelegate] didGetUserData]; return; } else { [MyApp setUserEtag:[[request responseHeaders] objectForKey:@"Etag"]]; [self importUserData:[request responseJSON]]; [[MyApp appDelegate] didGetUserData]; } } Apache Logs "GET /myhome.json HTTP/1.1" 200 5115 "-" "MyApp iPhone/1.0 (iPhone 3GS; 3.1.3)" "GET /myhome.json HTTP/1.1" 304 - "-" "MyApp iPhone/1.0 (iPhone 3GS; 3.1.3)" Wednesday, July 14, 2010
  • 77. Import On Launch class UsersController < ApplicationController def home if stale?(:etag => current_user) respond_to do |format| format.html { render :layout => 'application' } format.hmiphoneapp_json { render :json => current_user } end end end end Wednesday, July 14, 2010
  • 78. Import On Launch class UsersController < ApplicationController def home if stale?(:etag => current_user) respond_to do |format| format.html { render :layout => 'application' } format.hmiphoneapp_json { render :json => current_user } end end end end @implementation MyAppDelegate - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(clearEtag:) name:NSManagedObjectContextDidSaveNotification object:[HMApp moc]]; //... } - (void)clearEtag:(NSNotification *)notification { [MyApp removeUserEtag]; } @end Wednesday, July 14, 2010
  • 79. Models Drive @implementation MyManagedObject #pragma mark MyRequest Handling - (void)createRemoteFinished:(MyRequest *)request { if ([request isSuccessfulMyAppText]) { NSInteger *remoteInt = [[request responseString] integerValue]; NSNumber *remoteId = [NSNumber numberWithInteger:remoteInt]; [self setValue:remoteId forKey:@"remoteId"]; [self save]; } } @end Wednesday, July 14, 2010
  • 80. Models Drive @implementation MyManagedObject #pragma mark MyRequest Handling - (void)createRemoteFinished:(MyRequest *)request { if ([request isSuccessfulMyAppText]) { NSInteger *remoteInt = [[request responseString] integerValue]; NSNumber *remoteId = [NSNumber numberWithInteger:remoteInt]; [self setValue:remoteId forKey:@"remoteId"]; [self save]; } } @end @implementation HMColumn + (void)createRemote { HMColumn *newColumn = [[self class] newObject:nil]; //... [newColumn save]; [MyRequest columnCreate:newColumn]; [newColumn release]; } @end Wednesday, July 14, 2010
  • 81. @implementation HMColumn + (void)createRemote { HMColumn *newColumn = [[self class] newObject:nil]; //... [newColumn save]; [MyRequest columnCreate:newColumn]; [newColumn release]; } @end @implementation MyRequest + (void)columnCreate:(HMColumn *)column { MyFormRequest *request = [self myFormRequestFor:@"columns" withParams:nil]; request.delegate = column; request.didFinishSelector = @selector(createRemoteFinished:); request.didFailSelector = @selector(createRemoteFailed:); [[HMApp queue] addOperation:request]; } @end Wednesday, July 14, 2010
  • 82. Models Drive (box example) @implementation HMBox - (void)colorize { if ([[self changedValues] hasKey:@"style"] && [self save]) [HMRequest boxColorize:self]; } @end @implementation ASIHTTPRequest (MyAdditions) + (NSString *)box:(HMBox *)box action:(NSString *)action { return [NSString stringWithFormat:@"boxes/%@/%@",[[box remoteId] stringValue],action]; } + (void)boxColorize:(HMBox *)box { NSString *action = [self box:box action:@"colorize"]; NSDictionary *params = [NSDictionary dictionaryWithObjectsAndKeys:box.style,@"color",nil]; MyFormRequest *request = [self myPutRequestFor:action withParams:params]; [[MyApp queue] addOperation:request]; } @end Wednesday, July 14, 2010
  • 83. The End ( liked my talk – buy my app - write a review ) Wednesday, July 14, 2010