SlideShare a Scribd company logo
iPhone on Rails




    Mike Clark clarkware.com
(or Conventions Matter)
Hosted Rails App?


Fielded iPhone App?


     Neither?!
Rails
Installation




               $ sudo gem update --system
               $ sudo gem install rails
               $ sudo gem update rake
               $ sudo gem update sqlite3-ruby
Rails
Scaffold App




         $ rails expenses
         $ cd expenses


         $ script/generate scaffold expense 
                name:string amount:decimal


         $ rake db:migrate

         $ script/server



               http://localhost:3000/expenses
Rails Resource
Routes




     ActionController::Routing::Routes.draw do |map|
       map.resources :expenses
     end
Rails Resource
CRUD Routing




                 POST     /expenses/3

                 GET      /expenses

                 PUT      /expenses/3

                 DELETE   /expenses/3
Rails Resource
Controller


             class ExpensesController < ApplicationController

                 # GET /expenses
                 def index
                 end

                 # POST /expenses
                 def create
                 end

                 # GET /expenses/3
                 def show
                 end

                 # PUT /expenses/3
                 def update
                 end

                 # DELETE /expenses/3
                 def destroy
                 end

             end
Rails Resource
Model


   class Expense < ActiveRecord::Base
     validates_presence_of :name
     validates_numericality_of :amount,
                               :greater_than_or_equal_to => 0
   end




   Expense.create(:name => "iPod touch", :amount => 249.00)

   Expense.find(3)

   Expense.update(3, :amount => 199.00)

   Expense.destroy(3)
Rails Resource
View




       <p>
         <b>Name:</b>
         <%=h @expense.name %>
       </p>

       <p>
         <b>Amount:</b>
         <%=h @expense.amount %>
       </p>

       <%= link_to 'Edit', edit_expense_path(@expense) %> |
       <%= link_to 'Back', expenses_path %>
Rails
CRUD Conventions




         POST       GET      PUT     DELETE


        create     find     update   destroy


        INSERT     SELECT   UPDATE   DELETE
>> print Expense.find(3).to_xml

<?xml version="1.0" encoding="UTF-8"?>
<expense>
  <id type="integer">2</id>
  <name>iPod touch</name>
  <amount type="decimal">199.0</amount>
  <created-at type="datetime">2009-09-15T16:01:54Z</created-at>
  <updated-at type="datetime">2009-09-15T16:01:54Z</updated-at>
</expense>




>> print Expense.find(3).to_json

{"expense":
  {"id":2,
    "name":"iPod touch",
    "amount":199.0,
    "created_at":"2009-09-15T16:01:54Z",
    "updated_at":"2009-09-15T16:01:54Z"
  }
}
Rails Resource
Multi-Format Responses



      class ExpensesController < ApplicationController

         def show
           @expense = Expense.find(params[:id])

           respond_to do   |format|
             format.html   # show.html.erb
             format.xml    { render :xml => @expense }
             format.json   { render :json => @expense }
           end
         end

      end




               GET /expenses/3.{html|xml|json}
Rails
Security Tip




       class User < ActiveRecord::Base

          def to_xml(options={})
            options[:only] = [:id, :name, :screen_name]
            super(options)
          end

       end
iPhone
Scaffolding
iPhone
CRUD
iPhone CRUD
Roll Your Own

@implementation Expense

static NSString *siteURL = @"http://localhost:3000";

- (NSString *)params {
    return [NSString stringWithFormat:@"{"expense":{"name":"%@","amount":"%@"}}",
            self.name, self.amount];
}

- (void)createRemote {
    NSString *url = [NSString stringWithFormat:@"%@/expenses.json", siteURL];
    [Resource post:[self params] to:url];
}

+ (NSArray *)findAllRemote {
    NSString *url = [NSString stringWithFormat:@"%@/expenses.json", siteURL];
    NSString *jsonString = [Resource get:url];
    NSArray *expenses = // create expenses from JSON string
    return expenses;
}

- (void)updateRemote {
    NSString *url = [NSString stringWithFormat:@"%@/expenses/%@.json", siteURL, self.expenseId];
    [Resource put:[self params] to:url];
}

- (void)destroyRemote {
    NSString *url = [NSString stringWithFormat:@"%@/expenses/%@.json", siteURL, self.expenseId];
    [Resource delete:url];
}

@end
HTTPRiot

 Supports generic RESTful operations
 Converts JSON response to NSDictionary
 You decide what to do with the data
 Asynchronous



          http://github.com/Caged/httpriot
HTTPRiot
Configuration and Requests


[HRRestModel setDelegate:someObject];
[HRRestModel setBaseURL:[NSURL URLWithString:@"http://your-server/api"]];


[HRRestModel getPath:@"/expenses.json" withOptions:nil object:nil];



NSDictionary *options =
  [NSDictionary dictionaryWithObject:[expense JSONRepresentation] forKey:@"body"];
[HRRestModel postPath:@"/expenses" withOptions: options object:nil];



NSDictionary * options =
  [NSDictionary dictionaryWithObject:[expense JSONRepresentation] forKey:@"body"];
[HRRestModel putPath:@"/expenses/3" withOptions:options object:nil];




[HRRestModel deletePath:@"/expenses/3" withOptions:nil object:nil];
HTTPRiot
Callbacks


    - (void)restConnection:(NSURLConnection *)connection
         didReturnResource:(id)resource
                    object:(id)object {

        for (id item in resource) {
            Expense *expense = [[Expense alloc] initWithDictionary:item];
            // do something with expenses
        }
    }

    - (void)restConnection:(NSURLConnection *)connection
          didFailWithError:(NSError *)error
                    object:(id)object {
        // Handle connection errors
    }

    - (void)restConnection:(NSURLConnection *)connection
           didReceiveError:(NSError *)error
                  response:(NSHTTPURLResponse *)response
                    object:(id)object {
        // Handle invalid responses: 404, 500, and so on
    }

    - (void)restConnection:(NSURLConnection *)connection
      didReceiveParseError:(NSError *)error
              responseBody:(NSString *)string {
        // Request was successful, but couldn't parse the data returned by the server
    }
ASIHTTPRequest

 Super flexible with lots of features
 File uploads, progress indictors, etc.
 Uses CFNetwork API
 Asynchronous


        http://github.com/pokeb/asi-http-request
ASIHTTPRequest
Usage




 - (void)sendRequest {
    NSURL *url = [NSURL URLWithString:@"http://your-server.com/expenses.json"];
    ASIHTTPRequest *request = [[ASIHTTPRequest alloc] initWithURL:url];
    [request setDelegate:self];
    [request setDidFinishSelector:@selector(requestSucceeded:)];
    [request setDidFailSelector:@selector(requestFailed:)];
    [[self queue] addOperation:request];
    [request release];
 }

 - (void)requestSucceeded:(ASIHTTPRequest *)request {
    NSString *response = [request responseString];
 }

 - (void)requestFailed:(ASIHTTPRequest *)request {
    NSError *error = [request error];
 }
ObjectiveResource

 Objective-C port of ActiveResource
 Serializes to/from objects (XML or JSON)
 Assumes Rails RESTful conventions
 Asynchronous option in 1.1 branch


      http://github.com/yfactorial/objectiveresource
ObjectiveResource
Remote Resource


         #import "ObjectiveResource.h"

         @interface Expense : NSObject {
             NSString *expenseId;
             NSString *name;
             NSString *amount;
             NSDate   *createdAt;
             NSDate   *updatedAt;
         }

         @property   (nonatomic,   copy)     NSString   *expenseId;
         @property   (nonatomic,   copy)     NSString   *name;
         @property   (nonatomic,   copy)     NSString   *amount;
         @property   (nonatomic,   retain)   NSDate     *createdAt;
         @property   (nonatomic,   retain)   NSDate     *updatedAt;

         @end




                                                  * NSObject+ObjectiveResource category
ObjectiveResource
Configuration




 #import "ObjectiveResource.h"

 [ObjectiveResourceConfig setSite:@"http://your-server.com/"];
 [ObjectiveResourceConfig setResponseType:JSONResponse];
ObjectiveResource
CRUD Operations




        NSArray *expenses = [Expense findAllRemote];


        Expense *expense = [[Expense alloc] init];
        expense.name = @"iPod touch";
        [expense createRemote];


        Expense *expense = [Expense findRemote:@"3"];
        expense.name = @"iPhone";
        [expense updateRemote];



        [expense destroyRemote];
ObjectiveResource
Asynchronous Way




     [UIApplication sharedApplication].networkActivityIndicatorVisible = YES;
     [[ConnectionManager sharedInstance] runJob:@selector(loadExpenses)
                                       onTarget:self];



                                                * NSInvocationOperation in an NSOperationQueue




 - (void)loadExpenses {
     self.expenses = [Expense findAllRemote];

       [self.tableView performSelectorOnMainThread:@selector(reloadData)
                                        withObject:nil
                                     waitUntilDone:NO];

       [UIApplication sharedApplication].networkActivityIndicatorVisible = NO;
 }
iPhone
Nested Resources
Rails
Nested Resources




     ActionController::Routing::Routes.draw do |map|
       map.resources :budgets, :has_many => :expenses
     end
Rails
Nested Resource


      class ExpensesController < ApplicationController

        before_filter :find_budget

        def show
          @expense = @budget.expenses.find(params[:id])

          respond_to do |format|
            format.html
            format.xml { render :xml => @expense }
            format.json { render :json => @expense }
          end
        end

      private

        def find_budget
          @budget = current_user.budgets.find(params[:budget_id])
        end

      end


                   GET /budgets/6/expenses
ObjectiveResource
Nested Resources




    @implementation Budget

    @synthesize budgetId;

    - (NSArray *)findAllExpenses {
      return [Expense findRemote:[NSString stringWithFormat:@"%@/%@",
                                      self.budgetId, @"expenses"]];
    }

    @end




                    GET /budgets/6/expenses
ObjectiveResource
Nested Resources

     @implementation Expense

     @synthesize expenseId;
     @synthesize budgetId;

     + (NSString *)getRemoteCollectionName {
         return @"budgets";
     }

     - (NSString *)nestedPath {
         NSString *path = [NSString stringWithFormat:@"%@/expenses", self.budgetId];
         if (self.expenseId) {
             path = [path stringByAppendingFormat:@"/%@", self.expenseId];
         }
         return path;
     }

     - (BOOL)createRemoteWithResponse:(NSError **)aError {
         return [self createRemoteAtPath:[[self class] getRemoteElementPath:[self nestedPath]]
                            withResponse:aError];
     }

     - (BOOL)updateRemoteWithResponse:(NSError **)aError {
         return [self updateRemoteAtPath:[[self class] getRemoteElementPath:[self nestedPath]]
                            withResponse:aError];
     }

     - (BOOL)destroyRemoteWithResponse:(NSError **)aError {
         return [self destroyRemoteAtPath:[[self class] getRemoteElementPath:[self nestedPath]]
                             withResponse:aError];
     }

     @end
                                                                               * yeah, itʼs kinda clunky
iPhone & Rails
Authentication
Rails
Authentication



   class BudgetsController < ApplicationController

      before_filter :authenticate

      def index
        @budgets = current_user.budgets.all
      end

      def show
        @budget = current_user.budgets.find(params[:id])
      end

   private

      def current_user
        @current_user ||= User.find(session[:user_id])
      end

   end
Rails
Authentication


     def authenticate
       return if session[:user_id]

       respond_to do |format|
         format.html do
           redirect_to login_url
         end
         format.any(:xml, :json) do
           user = authenticate_with_http_basic do |username, password|
             User.authenticate(username, password)
           end
           if user
             session[:user_id] = user.id
           else
             request_http_basic_authentication
           end
         end
       end
     end
ObjectiveResource
Configuration




#import "ObjectiveResource.h"

[ObjectiveResourceConfig   setSite:@"http://your-server.com/"];
[ObjectiveResourceConfig   setResponseType:JSONResponse];
[ObjectiveResourceConfig   setUser:@"John"];
[ObjectiveResourceConfig   setPassword:@"Appleseed"];
RESTful web services are
resource based, stateless,
      and scaleable
http://github.com/clarkware
Hands-on iPhone and Rails
training from the folks who
      wrote the books

       pragmaticstudio.com

More Related Content

PDF
Introducing Assetic (NYPHP)
Kris Wallsmith
 
PDF
Silex Cheat Sheet
Andréia Bohner
 
PDF
Advanced symfony Techniques
Kris Wallsmith
 
PDF
Doctrine MongoDB ODM (PDXPHP)
Kris Wallsmith
 
PPT
Slim RedBeanPHP and Knockout
Vic Metcalfe
 
PDF
Keeping it Small: Getting to know the Slim Micro Framework
Jeremy Kendall
 
PDF
SPL: The Missing Link in Development
jsmith92
 
PPTX
A Functional Guide to Cat Herding with PHP Generators
Mark Baker
 
Introducing Assetic (NYPHP)
Kris Wallsmith
 
Silex Cheat Sheet
Andréia Bohner
 
Advanced symfony Techniques
Kris Wallsmith
 
Doctrine MongoDB ODM (PDXPHP)
Kris Wallsmith
 
Slim RedBeanPHP and Knockout
Vic Metcalfe
 
Keeping it Small: Getting to know the Slim Micro Framework
Jeremy Kendall
 
SPL: The Missing Link in Development
jsmith92
 
A Functional Guide to Cat Herding with PHP Generators
Mark Baker
 

What's hot (20)

PDF
Ethiopian multiplication in Perl6
Workhorse Computing
 
KEY
solving little problems
removed_e334947d661d520b05c7f698a45590c4
 
PDF
With a Mighty Hammer
Ben Scofield
 
KEY
ISUCONアプリを Pythonで書いてみた
memememomo
 
PDF
Lithium: The Framework for People Who Hate Frameworks, Tokyo Edition
Nate Abele
 
ODP
Perl5i
Marcos Rebelo
 
KEY
SQLite Techniques
Ben Scheirman
 
PDF
Building Cloud Castles
Ben Scofield
 
PDF
A Little Backbone For Your App
Luca Mearelli
 
PDF
Symfony tips and tricks
Mariusz Kozłowski
 
PDF
Keeping it small - Getting to know the Slim PHP micro framework
Jeremy Kendall
 
PPTX
A Functional Guide to Cat Herding with PHP Generators
Mark Baker
 
PDF
Controlling The Cloud With Python
Luca Mearelli
 
PPTX
Webrtc mojo
bpmedley
 
PPT
Nashvile Symfony Routes Presentation
Brent Shaffer
 
KEY
Keeping it small: Getting to know the Slim micro framework
Jeremy Kendall
 
PDF
The State of Lithium
Nate Abele
 
PDF
Perl6 Regexen: Reduce the line noise in your code.
Workhorse Computing
 
PDF
To Batch Or Not To Batch
Luca Mearelli
 
PDF
Forget about loops
Dušan Kasan
 
Ethiopian multiplication in Perl6
Workhorse Computing
 
With a Mighty Hammer
Ben Scofield
 
ISUCONアプリを Pythonで書いてみた
memememomo
 
Lithium: The Framework for People Who Hate Frameworks, Tokyo Edition
Nate Abele
 
SQLite Techniques
Ben Scheirman
 
Building Cloud Castles
Ben Scofield
 
A Little Backbone For Your App
Luca Mearelli
 
Symfony tips and tricks
Mariusz Kozłowski
 
Keeping it small - Getting to know the Slim PHP micro framework
Jeremy Kendall
 
A Functional Guide to Cat Herding with PHP Generators
Mark Baker
 
Controlling The Cloud With Python
Luca Mearelli
 
Webrtc mojo
bpmedley
 
Nashvile Symfony Routes Presentation
Brent Shaffer
 
Keeping it small: Getting to know the Slim micro framework
Jeremy Kendall
 
The State of Lithium
Nate Abele
 
Perl6 Regexen: Reduce the line noise in your code.
Workhorse Computing
 
To Batch Or Not To Batch
Luca Mearelli
 
Forget about loops
Dušan Kasan
 
Ad

Viewers also liked (19)

PPTX
Clase de RoboCup
Hisao Torres Jimenez
 
PPTX
Internet como fuente fiable de información económica
Universidad de Sevilla
 
PDF
Silicon Solar Brochure - EnviroLight Solar Billboard Lighting Systems
Silicon Solar
 
PDF
Strategic innovation in financial sector: Blockchain and the case of Spanish ...
Josep Grau Miró
 
DOC
Joseph Martin CV
Martin Lua
 
PDF
Identity Commons Presentation
Kaliya "Identity Woman" Young
 
PPTX
Autobiografía de Ainilda Patricia Ávila Laguna
Nina Manchola
 
PDF
Proyecto la recogida del olivo
gemaguillenc
 
PDF
Brochure P2S
vguili
 
DOC
Stopyra Resume
Sandra Stopyra
 
PDF
OSGi - Four Years and Forward - J Barr
mfrancis
 
PDF
El proceso de romanización de la provincia de huesca Labitolosa y La Vispera...
puebladecastro.blogspot
 
PPTX
Ecoaventura
Betzy Humpiri Velasquez
 
PDF
José María de las Heras - La integridad documental de los proyectos de ingeni...
COIICV
 
PDF
A new class of inkjet with HP PageWide Web Presses at drupa 2016
HP
 
PPTX
OneDrive for Business vs Arbeitsordner
Hans Brender
 
PPTX
Como configurar una IP Estatica en Windows XP y 7
Moy Martinez Dominguez
 
PDF
Lenguaje y tdah
Nataly Troncoso
 
PPT
Chapter 2 overview
ali raza
 
Clase de RoboCup
Hisao Torres Jimenez
 
Internet como fuente fiable de información económica
Universidad de Sevilla
 
Silicon Solar Brochure - EnviroLight Solar Billboard Lighting Systems
Silicon Solar
 
Strategic innovation in financial sector: Blockchain and the case of Spanish ...
Josep Grau Miró
 
Joseph Martin CV
Martin Lua
 
Identity Commons Presentation
Kaliya "Identity Woman" Young
 
Autobiografía de Ainilda Patricia Ávila Laguna
Nina Manchola
 
Proyecto la recogida del olivo
gemaguillenc
 
Brochure P2S
vguili
 
Stopyra Resume
Sandra Stopyra
 
OSGi - Four Years and Forward - J Barr
mfrancis
 
El proceso de romanización de la provincia de huesca Labitolosa y La Vispera...
puebladecastro.blogspot
 
José María de las Heras - La integridad documental de los proyectos de ingeni...
COIICV
 
A new class of inkjet with HP PageWide Web Presses at drupa 2016
HP
 
OneDrive for Business vs Arbeitsordner
Hans Brender
 
Como configurar una IP Estatica en Windows XP y 7
Moy Martinez Dominguez
 
Lenguaje y tdah
Nataly Troncoso
 
Chapter 2 overview
ali raza
 
Ad

Similar to I Phone On Rails (20)

PDF
Rails 3 overview
Yehuda Katz
 
PDF
Silex Cheat Sheet
Andréia Bohner
 
PDF
Rails 3: Dashing to the Finish
Yehuda Katz
 
PDF
Doctrine For Beginners
Jonathan Wage
 
PDF
Bootstrat REST APIs with Laravel 5
Elena Kolevska
 
PDF
Bag Of Tricks From Iusethis
Marcus Ramberg
 
KEY
SQLite Techniques
joaopmaia
 
KEY
Remedie: Building a desktop app with HTTP::Engine, SQLite and jQuery
Tatsuhiko Miyagawa
 
KEY
Zend framework service
Michelangelo van Dam
 
KEY
Zend framework service
Michelangelo van Dam
 
PDF
Building Lithium Apps
Nate Abele
 
KEY
Phpne august-2012-symfony-components-friends
Michael Peacock
 
PDF
Symfony2 from the Trenches
Jonathan Wage
 
ODP
Aura Project for PHP
Hari K T
 
PDF
WordPress REST API hacking
Jeroen van Dijk
 
PDF
関西PHP勉強会 php5.4つまみぐい
Hisateru Tanaka
 
PPT
GHC Participant Training
AidIQ
 
PDF
WordPress REST API hacking
Jeroen van Dijk
 
KEY
Zend Framework Study@Tokyo #2
Shinya Ohyanagi
 
PDF
Kicking off with Zend Expressive and Doctrine ORM (PHP UK 2017)
James Titcumb
 
Rails 3 overview
Yehuda Katz
 
Silex Cheat Sheet
Andréia Bohner
 
Rails 3: Dashing to the Finish
Yehuda Katz
 
Doctrine For Beginners
Jonathan Wage
 
Bootstrat REST APIs with Laravel 5
Elena Kolevska
 
Bag Of Tricks From Iusethis
Marcus Ramberg
 
SQLite Techniques
joaopmaia
 
Remedie: Building a desktop app with HTTP::Engine, SQLite and jQuery
Tatsuhiko Miyagawa
 
Zend framework service
Michelangelo van Dam
 
Zend framework service
Michelangelo van Dam
 
Building Lithium Apps
Nate Abele
 
Phpne august-2012-symfony-components-friends
Michael Peacock
 
Symfony2 from the Trenches
Jonathan Wage
 
Aura Project for PHP
Hari K T
 
WordPress REST API hacking
Jeroen van Dijk
 
関西PHP勉強会 php5.4つまみぐい
Hisateru Tanaka
 
GHC Participant Training
AidIQ
 
WordPress REST API hacking
Jeroen van Dijk
 
Zend Framework Study@Tokyo #2
Shinya Ohyanagi
 
Kicking off with Zend Expressive and Doctrine ORM (PHP UK 2017)
James Titcumb
 

More from John Wilker (20)

PDF
Cranking Floating Point Performance Up To 11
John Wilker
 
PDF
Introtoduction to cocos2d
John Wilker
 
PDF
Getting Started with OpenGL ES
John Wilker
 
PDF
User Input in a multi-touch, accelerometer, location aware world.
John Wilker
 
PDF
Physics Solutions for Innovative Game Design
John Wilker
 
PDF
Getting Oriented with MapKit: Everything you need to get started with the new...
John Wilker
 
PDF
Getting Started with iPhone Game Development
John Wilker
 
PDF
Internationalizing Your Apps
John Wilker
 
PDF
Optimizing Data Caching for iPhone Application Responsiveness
John Wilker
 
PDF
Integrating Push Notifications in your iPhone application with iLime
John Wilker
 
PDF
Starting Core Animation
John Wilker
 
PDF
P2P Multiplayer Gaming
John Wilker
 
PDF
Using Concurrency To Improve Responsiveness
John Wilker
 
PDF
Leaving Interface Builder Behind
John Wilker
 
PDF
Mobile WebKit Development and jQTouch
John Wilker
 
PDF
Accelerometer and OpenGL
John Wilker
 
PDF
Deep Geek Diving into the iPhone OS and Framework
John Wilker
 
PDF
NSNotificationCenter vs. AppDelegate
John Wilker
 
PDF
Using SQLite
John Wilker
 
PDF
From Flash to iPhone
John Wilker
 
Cranking Floating Point Performance Up To 11
John Wilker
 
Introtoduction to cocos2d
John Wilker
 
Getting Started with OpenGL ES
John Wilker
 
User Input in a multi-touch, accelerometer, location aware world.
John Wilker
 
Physics Solutions for Innovative Game Design
John Wilker
 
Getting Oriented with MapKit: Everything you need to get started with the new...
John Wilker
 
Getting Started with iPhone Game Development
John Wilker
 
Internationalizing Your Apps
John Wilker
 
Optimizing Data Caching for iPhone Application Responsiveness
John Wilker
 
Integrating Push Notifications in your iPhone application with iLime
John Wilker
 
Starting Core Animation
John Wilker
 
P2P Multiplayer Gaming
John Wilker
 
Using Concurrency To Improve Responsiveness
John Wilker
 
Leaving Interface Builder Behind
John Wilker
 
Mobile WebKit Development and jQTouch
John Wilker
 
Accelerometer and OpenGL
John Wilker
 
Deep Geek Diving into the iPhone OS and Framework
John Wilker
 
NSNotificationCenter vs. AppDelegate
John Wilker
 
Using SQLite
John Wilker
 
From Flash to iPhone
John Wilker
 

Recently uploaded (20)

PDF
A Strategic Analysis of the MVNO Wave in Emerging Markets.pdf
IPLOOK Networks
 
PDF
SparkLabs Primer on Artificial Intelligence 2025
SparkLabs Group
 
PDF
OFFOFFBOX™ – A New Era for African Film | Startup Presentation
ambaicciwalkerbrian
 
PPTX
AI in Daily Life: How Artificial Intelligence Helps Us Every Day
vanshrpatil7
 
PDF
MASTERDECK GRAPHSUMMIT SYDNEY (Public).pdf
Neo4j
 
PDF
Peak of Data & AI Encore - Real-Time Insights & Scalable Editing with ArcGIS
Safe Software
 
PDF
Make GenAI investments go further with the Dell AI Factory
Principled Technologies
 
PDF
Oracle AI Vector Search- Getting Started and what's new in 2025- AIOUG Yatra ...
Sandesh Rao
 
PDF
Automating ArcGIS Content Discovery with FME: A Real World Use Case
Safe Software
 
PDF
Responsible AI and AI Ethics - By Sylvester Ebhonu
Sylvester Ebhonu
 
PDF
How Open Source Changed My Career by abdelrahman ismail
a0m0rajab1
 
PPTX
What-is-the-World-Wide-Web -- Introduction
tonifi9488
 
PPTX
Introduction to Flutter by Ayush Desai.pptx
ayushdesai204
 
PDF
Economic Impact of Data Centres to the Malaysian Economy
flintglobalapac
 
PDF
Using Anchore and DefectDojo to Stand Up Your DevSecOps Function
Anchore
 
PDF
Orbitly Pitch Deck|A Mission-Driven Platform for Side Project Collaboration (...
zz41354899
 
PPTX
OA presentation.pptx OA presentation.pptx
pateldhruv002338
 
PDF
Tea4chat - another LLM Project by Kerem Atam
a0m0rajab1
 
PDF
Trying to figure out MCP by actually building an app from scratch with open s...
Julien SIMON
 
PPTX
Applied-Statistics-Mastering-Data-Driven-Decisions.pptx
parmaryashparmaryash
 
A Strategic Analysis of the MVNO Wave in Emerging Markets.pdf
IPLOOK Networks
 
SparkLabs Primer on Artificial Intelligence 2025
SparkLabs Group
 
OFFOFFBOX™ – A New Era for African Film | Startup Presentation
ambaicciwalkerbrian
 
AI in Daily Life: How Artificial Intelligence Helps Us Every Day
vanshrpatil7
 
MASTERDECK GRAPHSUMMIT SYDNEY (Public).pdf
Neo4j
 
Peak of Data & AI Encore - Real-Time Insights & Scalable Editing with ArcGIS
Safe Software
 
Make GenAI investments go further with the Dell AI Factory
Principled Technologies
 
Oracle AI Vector Search- Getting Started and what's new in 2025- AIOUG Yatra ...
Sandesh Rao
 
Automating ArcGIS Content Discovery with FME: A Real World Use Case
Safe Software
 
Responsible AI and AI Ethics - By Sylvester Ebhonu
Sylvester Ebhonu
 
How Open Source Changed My Career by abdelrahman ismail
a0m0rajab1
 
What-is-the-World-Wide-Web -- Introduction
tonifi9488
 
Introduction to Flutter by Ayush Desai.pptx
ayushdesai204
 
Economic Impact of Data Centres to the Malaysian Economy
flintglobalapac
 
Using Anchore and DefectDojo to Stand Up Your DevSecOps Function
Anchore
 
Orbitly Pitch Deck|A Mission-Driven Platform for Side Project Collaboration (...
zz41354899
 
OA presentation.pptx OA presentation.pptx
pateldhruv002338
 
Tea4chat - another LLM Project by Kerem Atam
a0m0rajab1
 
Trying to figure out MCP by actually building an app from scratch with open s...
Julien SIMON
 
Applied-Statistics-Mastering-Data-Driven-Decisions.pptx
parmaryashparmaryash
 

I Phone On Rails

  • 1. iPhone on Rails Mike Clark clarkware.com
  • 3. Hosted Rails App? Fielded iPhone App? Neither?!
  • 4. Rails Installation $ sudo gem update --system $ sudo gem install rails $ sudo gem update rake $ sudo gem update sqlite3-ruby
  • 5. Rails Scaffold App $ rails expenses $ cd expenses $ script/generate scaffold expense name:string amount:decimal $ rake db:migrate $ script/server http://localhost:3000/expenses
  • 6. Rails Resource Routes ActionController::Routing::Routes.draw do |map| map.resources :expenses end
  • 7. Rails Resource CRUD Routing POST /expenses/3 GET /expenses PUT /expenses/3 DELETE /expenses/3
  • 8. Rails Resource Controller class ExpensesController < ApplicationController # GET /expenses def index end # POST /expenses def create end # GET /expenses/3 def show end # PUT /expenses/3 def update end # DELETE /expenses/3 def destroy end end
  • 9. Rails Resource Model class Expense < ActiveRecord::Base validates_presence_of :name validates_numericality_of :amount, :greater_than_or_equal_to => 0 end Expense.create(:name => "iPod touch", :amount => 249.00) Expense.find(3) Expense.update(3, :amount => 199.00) Expense.destroy(3)
  • 10. Rails Resource View <p> <b>Name:</b> <%=h @expense.name %> </p> <p> <b>Amount:</b> <%=h @expense.amount %> </p> <%= link_to 'Edit', edit_expense_path(@expense) %> | <%= link_to 'Back', expenses_path %>
  • 11. Rails CRUD Conventions POST GET PUT DELETE create find update destroy INSERT SELECT UPDATE DELETE
  • 12. >> print Expense.find(3).to_xml <?xml version="1.0" encoding="UTF-8"?> <expense> <id type="integer">2</id> <name>iPod touch</name> <amount type="decimal">199.0</amount> <created-at type="datetime">2009-09-15T16:01:54Z</created-at> <updated-at type="datetime">2009-09-15T16:01:54Z</updated-at> </expense> >> print Expense.find(3).to_json {"expense": {"id":2, "name":"iPod touch", "amount":199.0, "created_at":"2009-09-15T16:01:54Z", "updated_at":"2009-09-15T16:01:54Z" } }
  • 13. Rails Resource Multi-Format Responses class ExpensesController < ApplicationController def show @expense = Expense.find(params[:id]) respond_to do |format| format.html # show.html.erb format.xml { render :xml => @expense } format.json { render :json => @expense } end end end GET /expenses/3.{html|xml|json}
  • 14. Rails Security Tip class User < ActiveRecord::Base def to_xml(options={}) options[:only] = [:id, :name, :screen_name] super(options) end end
  • 17. iPhone CRUD Roll Your Own @implementation Expense static NSString *siteURL = @"http://localhost:3000"; - (NSString *)params { return [NSString stringWithFormat:@"{"expense":{"name":"%@","amount":"%@"}}", self.name, self.amount]; } - (void)createRemote { NSString *url = [NSString stringWithFormat:@"%@/expenses.json", siteURL]; [Resource post:[self params] to:url]; } + (NSArray *)findAllRemote { NSString *url = [NSString stringWithFormat:@"%@/expenses.json", siteURL]; NSString *jsonString = [Resource get:url]; NSArray *expenses = // create expenses from JSON string return expenses; } - (void)updateRemote { NSString *url = [NSString stringWithFormat:@"%@/expenses/%@.json", siteURL, self.expenseId]; [Resource put:[self params] to:url]; } - (void)destroyRemote { NSString *url = [NSString stringWithFormat:@"%@/expenses/%@.json", siteURL, self.expenseId]; [Resource delete:url]; } @end
  • 18. HTTPRiot Supports generic RESTful operations Converts JSON response to NSDictionary You decide what to do with the data Asynchronous http://github.com/Caged/httpriot
  • 19. HTTPRiot Configuration and Requests [HRRestModel setDelegate:someObject]; [HRRestModel setBaseURL:[NSURL URLWithString:@"http://your-server/api"]]; [HRRestModel getPath:@"/expenses.json" withOptions:nil object:nil]; NSDictionary *options = [NSDictionary dictionaryWithObject:[expense JSONRepresentation] forKey:@"body"]; [HRRestModel postPath:@"/expenses" withOptions: options object:nil]; NSDictionary * options = [NSDictionary dictionaryWithObject:[expense JSONRepresentation] forKey:@"body"]; [HRRestModel putPath:@"/expenses/3" withOptions:options object:nil]; [HRRestModel deletePath:@"/expenses/3" withOptions:nil object:nil];
  • 20. HTTPRiot Callbacks - (void)restConnection:(NSURLConnection *)connection didReturnResource:(id)resource object:(id)object { for (id item in resource) { Expense *expense = [[Expense alloc] initWithDictionary:item]; // do something with expenses } } - (void)restConnection:(NSURLConnection *)connection didFailWithError:(NSError *)error object:(id)object { // Handle connection errors } - (void)restConnection:(NSURLConnection *)connection didReceiveError:(NSError *)error response:(NSHTTPURLResponse *)response object:(id)object { // Handle invalid responses: 404, 500, and so on } - (void)restConnection:(NSURLConnection *)connection didReceiveParseError:(NSError *)error responseBody:(NSString *)string { // Request was successful, but couldn't parse the data returned by the server }
  • 21. ASIHTTPRequest Super flexible with lots of features File uploads, progress indictors, etc. Uses CFNetwork API Asynchronous http://github.com/pokeb/asi-http-request
  • 22. ASIHTTPRequest Usage - (void)sendRequest { NSURL *url = [NSURL URLWithString:@"http://your-server.com/expenses.json"]; ASIHTTPRequest *request = [[ASIHTTPRequest alloc] initWithURL:url]; [request setDelegate:self]; [request setDidFinishSelector:@selector(requestSucceeded:)]; [request setDidFailSelector:@selector(requestFailed:)]; [[self queue] addOperation:request]; [request release]; } - (void)requestSucceeded:(ASIHTTPRequest *)request { NSString *response = [request responseString]; } - (void)requestFailed:(ASIHTTPRequest *)request { NSError *error = [request error]; }
  • 23. ObjectiveResource Objective-C port of ActiveResource Serializes to/from objects (XML or JSON) Assumes Rails RESTful conventions Asynchronous option in 1.1 branch http://github.com/yfactorial/objectiveresource
  • 24. ObjectiveResource Remote Resource #import "ObjectiveResource.h" @interface Expense : NSObject { NSString *expenseId; NSString *name; NSString *amount; NSDate *createdAt; NSDate *updatedAt; } @property (nonatomic, copy) NSString *expenseId; @property (nonatomic, copy) NSString *name; @property (nonatomic, copy) NSString *amount; @property (nonatomic, retain) NSDate *createdAt; @property (nonatomic, retain) NSDate *updatedAt; @end * NSObject+ObjectiveResource category
  • 25. ObjectiveResource Configuration #import "ObjectiveResource.h" [ObjectiveResourceConfig setSite:@"http://your-server.com/"]; [ObjectiveResourceConfig setResponseType:JSONResponse];
  • 26. ObjectiveResource CRUD Operations NSArray *expenses = [Expense findAllRemote]; Expense *expense = [[Expense alloc] init]; expense.name = @"iPod touch"; [expense createRemote]; Expense *expense = [Expense findRemote:@"3"]; expense.name = @"iPhone"; [expense updateRemote]; [expense destroyRemote];
  • 27. ObjectiveResource Asynchronous Way [UIApplication sharedApplication].networkActivityIndicatorVisible = YES; [[ConnectionManager sharedInstance] runJob:@selector(loadExpenses) onTarget:self]; * NSInvocationOperation in an NSOperationQueue - (void)loadExpenses { self.expenses = [Expense findAllRemote]; [self.tableView performSelectorOnMainThread:@selector(reloadData) withObject:nil waitUntilDone:NO]; [UIApplication sharedApplication].networkActivityIndicatorVisible = NO; }
  • 29. Rails Nested Resources ActionController::Routing::Routes.draw do |map| map.resources :budgets, :has_many => :expenses end
  • 30. Rails Nested Resource class ExpensesController < ApplicationController before_filter :find_budget def show @expense = @budget.expenses.find(params[:id]) respond_to do |format| format.html format.xml { render :xml => @expense } format.json { render :json => @expense } end end private def find_budget @budget = current_user.budgets.find(params[:budget_id]) end end GET /budgets/6/expenses
  • 31. ObjectiveResource Nested Resources @implementation Budget @synthesize budgetId; - (NSArray *)findAllExpenses { return [Expense findRemote:[NSString stringWithFormat:@"%@/%@", self.budgetId, @"expenses"]]; } @end GET /budgets/6/expenses
  • 32. ObjectiveResource Nested Resources @implementation Expense @synthesize expenseId; @synthesize budgetId; + (NSString *)getRemoteCollectionName { return @"budgets"; } - (NSString *)nestedPath { NSString *path = [NSString stringWithFormat:@"%@/expenses", self.budgetId]; if (self.expenseId) { path = [path stringByAppendingFormat:@"/%@", self.expenseId]; } return path; } - (BOOL)createRemoteWithResponse:(NSError **)aError { return [self createRemoteAtPath:[[self class] getRemoteElementPath:[self nestedPath]] withResponse:aError]; } - (BOOL)updateRemoteWithResponse:(NSError **)aError { return [self updateRemoteAtPath:[[self class] getRemoteElementPath:[self nestedPath]] withResponse:aError]; } - (BOOL)destroyRemoteWithResponse:(NSError **)aError { return [self destroyRemoteAtPath:[[self class] getRemoteElementPath:[self nestedPath]] withResponse:aError]; } @end * yeah, itʼs kinda clunky
  • 34. Rails Authentication class BudgetsController < ApplicationController before_filter :authenticate def index @budgets = current_user.budgets.all end def show @budget = current_user.budgets.find(params[:id]) end private def current_user @current_user ||= User.find(session[:user_id]) end end
  • 35. Rails Authentication def authenticate return if session[:user_id] respond_to do |format| format.html do redirect_to login_url end format.any(:xml, :json) do user = authenticate_with_http_basic do |username, password| User.authenticate(username, password) end if user session[:user_id] = user.id else request_http_basic_authentication end end end end
  • 36. ObjectiveResource Configuration #import "ObjectiveResource.h" [ObjectiveResourceConfig setSite:@"http://your-server.com/"]; [ObjectiveResourceConfig setResponseType:JSONResponse]; [ObjectiveResourceConfig setUser:@"John"]; [ObjectiveResourceConfig setPassword:@"Appleseed"];
  • 37. RESTful web services are resource based, stateless, and scaleable
  • 39. Hands-on iPhone and Rails training from the folks who wrote the books pragmaticstudio.com