SlideShare a Scribd company logo
1 of 20
Building an iPhone app
with Rails and no Objective-C
Texas Association of Local Health Officials
Richard Boldway - rboldway@talho.org
Andrew Duhan - andrewduhan@gmail.com
Intro to Problem
● Build an iPhone interface to TxPhin application
● Restrict access by login
● Show list of latest alerts
● Search directory information
● Mandatory: iTunes AppStore delivery
Client - github.com/talho/iPHIN/
Objective-C ?
● Barriers to entry:
– Language learning curve
– Environment learning curve
– Memory Management: #1 killer of iPhone apps
● Why write a client-app for an already web-
enabled system?
Choice of Tools
● Appcelerator (appcelerator.com)
● Rhodes (rhomobile.com)
● Jqtouch (jqtouch.com)
● PhoneGap (phonegap.com)
● Roll-our-own
PhoneGap
● Runs a local web server
● Displays through full screen Safari
– Removes non-app elements
● Supports local, session, sqlite storage
● Access to iPhone resources via Javascript
– Accelerometer
– Contact manager and place calls
– GPS
– No camera & microphone
AppStore Submission Tips
● Graceful Network Error Handling
● No High Data Volume/Request
● No Desktop/Widget environment
● No major UI/UX from the server
appreview.tumblr.com
RAILS Integration
● Preferred to make controllers accept JSON via
AJAX
– Search controller
– Alerts controller
● Only fetching pieces of page data at a time
JSONP
● JSONP works, but...
● Concern about security
● Concern about apple rejection (eval)
● Rack hack for POST to support CRUD
Client side:
$.ajax({type: "GET",
url: “https://localhost:3000/session.json",
data: "session[login]=bill24&session[password]=password",
dataType: "jsonp", cache: false,
success: function(data){ alert(data.test); } //alerts 'me'
});
Rack App:
require(File.dirname(__FILE__) + "/../../config/environment")
unless defined?(Rails)
class TestRack
def self.call(env)
if env["REQUEST_METHOD"] == "GET" &&
env["QUERY_STRING"] =~ /callback=jsonp/
env["REQUEST_METHOD"] = "POST"
end
[404, {"Content-Type" => "text/html"}, "Hello World."]
end
end
Rails controller action:
format.json {
render :json => "#{params[:callback]}({'test': 'me'})"
}
CORS - w3.org/TR/cors
● Rails auto-token magic
– (don't try this without SSL)
● Extra necessary headers
– Access-Control-Allow-Origin
– Access-Control-Allow-Methods
– Access-Control-Allow-Headers
– Access-Control-Max-Age
● Option action / Pre-flighting JSON request
– Invisible in Webkit Inspector
Preflighted Request AJAX (post)
sessions_controller.rb
# iPhone app
format.json {
sign_in(@user)
remember(@user) if remember?
headers["Access-Control-Allow-Origin"] = "*"
render :json => {
:token => form_authenticity_token,
:cookie =>
"#{ActionController::Base.session_options[:key]}= 
#{ActiveSupport::MessageVerifier.new( 
ActionController::Base.session_options[:secret],
'SHA1').generate(session.to_hash)}"
}
}
routes.rb
map.connect "/session.:format",
:controller => "application",
:action => "options",
:conditions => {:method => [:options]}
application_controller.rb
def options
render :nothing => true, :status => 200
end
before_filter :add_cors_header, :only => :options
private
def add_cors_header
# Allows for Cross-Origin Resource Sharing
headers["Access-Control-Allow-Origin"] = "*"
headers["Access-Control-Allow-Methods"] = "OPTIONS"
headers["Access-Control-Allow-Headers"] = 
"X-Requested-With, Cookie"
headers["Access-Control-Max-Age"] = "1728000"
end
client side:
$.ajax({ type: "POST",
data: $('#signin_form').serialize(),
dataType: "json",
url: DOMAIN + "/session.json",
timeout: 10000, cache: false,
success: function(data) {
setCookie(data);
setTimeout(function() {
jQT.goTo($('#alerts_pane'), 'flip');
$('#signin_pane').data('clicked', false);
}, 500);
},
error: function(xhr) {
$('#signin_pane').data('clicked', false);
if (xhr.readyState == 4){
switch (xhr.status) {
Case 401: msg(...); break; // bad user or pass
case 0: msg(...); break; // bad user or pass
default: msg(...); // Network error
}
} else {
msg ('Error contacting server.');
}
}
});
Error handling
● Many errors are un-meaningful
● JQTouch uses older jQuery;
always returns XHR success :-/
● Server dead? Or lost Network?
– Reachability API in PhoneGap
iPhone UI Concerns
● jQTouch is dead.
● iPhone tap delay
– Double click
– History issues
● Jquery behavior
– window['localStorage']._cookie
– $('body').data(obj)
● Large <select> lists are painful
What would we do today?
● Rails – Generally very happy
– Alias .iphone to text/json, avoiding base JSON
handler confusion
● Alternatives to jQTouch
– SenchaTouch (ext.js): very iPhoney but
Android-compatible
– jQuery Mobile: Very new, lots of devices, more
generic
– Jo App: Ditto.
● Skip the app store?
Thank You!
txphin.org
github.com/talho

More Related Content

Viewers also liked (9)

Complex Division Splitting Assets in a California Divorce
Complex Division Splitting Assets in a California DivorceComplex Division Splitting Assets in a California Divorce
Complex Division Splitting Assets in a California Divorce
 
교육평가
교육평가교육평가
교육평가
 
Software Educativo
Software EducativoSoftware Educativo
Software Educativo
 
디미컨2 01
디미컨2 01디미컨2 01
디미컨2 01
 
매드헌터 07 수정02
매드헌터 07 수정02매드헌터 07 수정02
매드헌터 07 수정02
 
어린이 안전재난 교육 최린아 이혜인 이소담 중간발표02
어린이 안전재난 교육 최린아 이혜인 이소담 중간발표02어린이 안전재난 교육 최린아 이혜인 이소담 중간발표02
어린이 안전재난 교육 최린아 이혜인 이소담 중간발표02
 
교육평가
교육평가교육평가
교육평가
 
Yeastar IP-PBX Introduction
Yeastar IP-PBX IntroductionYeastar IP-PBX Introduction
Yeastar IP-PBX Introduction
 
Sangoma Vega Gateways
Sangoma Vega GatewaysSangoma Vega Gateways
Sangoma Vega Gateways
 

Similar to AOR-outline-2

Similar to AOR-outline-2 (20)

High Availability by Design
High Availability by DesignHigh Availability by Design
High Availability by Design
 
SenchaCon 2016: A Look Ahead: Survey Next-Gen Modern Browser APIs - Shikhir S...
SenchaCon 2016: A Look Ahead: Survey Next-Gen Modern Browser APIs - Shikhir S...SenchaCon 2016: A Look Ahead: Survey Next-Gen Modern Browser APIs - Shikhir S...
SenchaCon 2016: A Look Ahead: Survey Next-Gen Modern Browser APIs - Shikhir S...
 
Web Services and Android - OSSPAC 2009
Web Services and Android - OSSPAC 2009Web Services and Android - OSSPAC 2009
Web Services and Android - OSSPAC 2009
 
HTML5 on Mobile
HTML5 on MobileHTML5 on Mobile
HTML5 on Mobile
 
Connecting to Web Services on Android
Connecting to Web Services on AndroidConnecting to Web Services on Android
Connecting to Web Services on Android
 
Modern Web Applications Utilizing HTML5 APIs
Modern Web Applications Utilizing HTML5 APIsModern Web Applications Utilizing HTML5 APIs
Modern Web Applications Utilizing HTML5 APIs
 
Google I/O 2012 - Protecting your user experience while integrating 3rd party...
Google I/O 2012 - Protecting your user experience while integrating 3rd party...Google I/O 2012 - Protecting your user experience while integrating 3rd party...
Google I/O 2012 - Protecting your user experience while integrating 3rd party...
 
Introducere in web
Introducere in webIntroducere in web
Introducere in web
 
How NOT to get lost in the current JavaScript landscape
How NOT to get lost in the current JavaScript landscapeHow NOT to get lost in the current JavaScript landscape
How NOT to get lost in the current JavaScript landscape
 
Araport Workshop Tutorial 2: Authentication and the Agave Profiles Service
Araport Workshop Tutorial 2: Authentication and the Agave Profiles ServiceAraport Workshop Tutorial 2: Authentication and the Agave Profiles Service
Araport Workshop Tutorial 2: Authentication and the Agave Profiles Service
 
Graphing for Security
Graphing for SecurityGraphing for Security
Graphing for Security
 
API Security - OWASP top 10 for APIs + tips for pentesters
API Security - OWASP top 10 for APIs + tips for pentestersAPI Security - OWASP top 10 for APIs + tips for pentesters
API Security - OWASP top 10 for APIs + tips for pentesters
 
How to build Simple yet powerful API.pptx
How to build Simple yet powerful API.pptxHow to build Simple yet powerful API.pptx
How to build Simple yet powerful API.pptx
 
Utilizing HTML5 APIs
Utilizing HTML5 APIsUtilizing HTML5 APIs
Utilizing HTML5 APIs
 
Scraping the web with Laravel, Dusk, Docker, and PHP
Scraping the web with Laravel, Dusk, Docker, and PHPScraping the web with Laravel, Dusk, Docker, and PHP
Scraping the web with Laravel, Dusk, Docker, and PHP
 
Monitoring a Kubernetes-backed microservice architecture with Prometheus
Monitoring a Kubernetes-backed microservice architecture with PrometheusMonitoring a Kubernetes-backed microservice architecture with Prometheus
Monitoring a Kubernetes-backed microservice architecture with Prometheus
 
Globus Platform Overview
Globus Platform OverviewGlobus Platform Overview
Globus Platform Overview
 
Security Best Practices for Bot Builders
Security Best Practices for Bot BuildersSecurity Best Practices for Bot Builders
Security Best Practices for Bot Builders
 
Don Thorp & Marshall Culpepper: Advanced Titanium Development for Android
Don Thorp & Marshall Culpepper: Advanced Titanium Development for AndroidDon Thorp & Marshall Culpepper: Advanced Titanium Development for Android
Don Thorp & Marshall Culpepper: Advanced Titanium Development for Android
 
Node.js Course 2 of 2 - Advanced techniques
Node.js Course 2 of 2 - Advanced techniquesNode.js Course 2 of 2 - Advanced techniques
Node.js Course 2 of 2 - Advanced techniques
 

AOR-outline-2

  • 1. Building an iPhone app with Rails and no Objective-C Texas Association of Local Health Officials Richard Boldway - rboldway@talho.org Andrew Duhan - andrewduhan@gmail.com
  • 2.
  • 3.
  • 4. Intro to Problem ● Build an iPhone interface to TxPhin application ● Restrict access by login ● Show list of latest alerts ● Search directory information ● Mandatory: iTunes AppStore delivery Client - github.com/talho/iPHIN/
  • 5. Objective-C ? ● Barriers to entry: – Language learning curve – Environment learning curve – Memory Management: #1 killer of iPhone apps ● Why write a client-app for an already web- enabled system?
  • 6. Choice of Tools ● Appcelerator (appcelerator.com) ● Rhodes (rhomobile.com) ● Jqtouch (jqtouch.com) ● PhoneGap (phonegap.com) ● Roll-our-own
  • 7. PhoneGap ● Runs a local web server ● Displays through full screen Safari – Removes non-app elements ● Supports local, session, sqlite storage ● Access to iPhone resources via Javascript – Accelerometer – Contact manager and place calls – GPS – No camera & microphone
  • 8. AppStore Submission Tips ● Graceful Network Error Handling ● No High Data Volume/Request ● No Desktop/Widget environment ● No major UI/UX from the server appreview.tumblr.com
  • 9. RAILS Integration ● Preferred to make controllers accept JSON via AJAX – Search controller – Alerts controller ● Only fetching pieces of page data at a time
  • 10. JSONP ● JSONP works, but... ● Concern about security ● Concern about apple rejection (eval) ● Rack hack for POST to support CRUD
  • 11. Client side: $.ajax({type: "GET", url: “https://localhost:3000/session.json", data: "session[login]=bill24&session[password]=password", dataType: "jsonp", cache: false, success: function(data){ alert(data.test); } //alerts 'me' }); Rack App: require(File.dirname(__FILE__) + "/../../config/environment") unless defined?(Rails) class TestRack def self.call(env) if env["REQUEST_METHOD"] == "GET" && env["QUERY_STRING"] =~ /callback=jsonp/ env["REQUEST_METHOD"] = "POST" end [404, {"Content-Type" => "text/html"}, "Hello World."] end end Rails controller action: format.json { render :json => "#{params[:callback]}({'test': 'me'})" }
  • 12. CORS - w3.org/TR/cors ● Rails auto-token magic – (don't try this without SSL) ● Extra necessary headers – Access-Control-Allow-Origin – Access-Control-Allow-Methods – Access-Control-Allow-Headers – Access-Control-Max-Age ● Option action / Pre-flighting JSON request – Invisible in Webkit Inspector
  • 14. sessions_controller.rb # iPhone app format.json { sign_in(@user) remember(@user) if remember? headers["Access-Control-Allow-Origin"] = "*" render :json => { :token => form_authenticity_token, :cookie => "#{ActionController::Base.session_options[:key]}= #{ActiveSupport::MessageVerifier.new( ActionController::Base.session_options[:secret], 'SHA1').generate(session.to_hash)}" } } routes.rb map.connect "/session.:format", :controller => "application", :action => "options", :conditions => {:method => [:options]}
  • 15. application_controller.rb def options render :nothing => true, :status => 200 end before_filter :add_cors_header, :only => :options private def add_cors_header # Allows for Cross-Origin Resource Sharing headers["Access-Control-Allow-Origin"] = "*" headers["Access-Control-Allow-Methods"] = "OPTIONS" headers["Access-Control-Allow-Headers"] = "X-Requested-With, Cookie" headers["Access-Control-Max-Age"] = "1728000" end
  • 16. client side: $.ajax({ type: "POST", data: $('#signin_form').serialize(), dataType: "json", url: DOMAIN + "/session.json", timeout: 10000, cache: false, success: function(data) { setCookie(data); setTimeout(function() { jQT.goTo($('#alerts_pane'), 'flip'); $('#signin_pane').data('clicked', false); }, 500); }, error: function(xhr) { $('#signin_pane').data('clicked', false); if (xhr.readyState == 4){ switch (xhr.status) { Case 401: msg(...); break; // bad user or pass case 0: msg(...); break; // bad user or pass default: msg(...); // Network error } } else { msg ('Error contacting server.'); } } });
  • 17. Error handling ● Many errors are un-meaningful ● JQTouch uses older jQuery; always returns XHR success :-/ ● Server dead? Or lost Network? – Reachability API in PhoneGap
  • 18. iPhone UI Concerns ● jQTouch is dead. ● iPhone tap delay – Double click – History issues ● Jquery behavior – window['localStorage']._cookie – $('body').data(obj) ● Large <select> lists are painful
  • 19. What would we do today? ● Rails – Generally very happy – Alias .iphone to text/json, avoiding base JSON handler confusion ● Alternatives to jQTouch – SenchaTouch (ext.js): very iPhoney but Android-compatible – jQuery Mobile: Very new, lots of devices, more generic – Jo App: Ditto. ● Skip the app store?