Rails Sojourn: One Man's Journey - Wicked Good Ruby Conference 2013

94
RAILS SOJOURN: ONE MAN’S JOURNEY Mike Desjardins Monday, October 14, 13

description

With several spawling, monolithic Rails apps under my belt, I had the opportunity to go a different route. Bulging models, obtuse controllers, and views chock full of logic were my world. When I came up for air, all the cool kids were writing thick clients with svelte backends. Perhaps Sinatra and some hip Javascript framework were the way? Here's what I learned...

Transcript of Rails Sojourn: One Man's Journey - Wicked Good Ruby Conference 2013

Page 1: Rails Sojourn: One Man's Journey - Wicked Good Ruby Conference 2013

RAILS SOJOURN: ONE MAN’S

JOURNEYMike Desjardins

Monday, October 14, 13

Page 2: Rails Sojourn: One Man's Journey - Wicked Good Ruby Conference 2013

HI, I’M MIKE!

I’M FROM PORTLAND

Monday, October 14, 13

Page 3: Rails Sojourn: One Man's Journey - Wicked Good Ruby Conference 2013

NO, NOT THAT PORTLANDMonday, October 14, 13

Page 4: Rails Sojourn: One Man's Journey - Wicked Good Ruby Conference 2013

THIS PORTLANDMonday, October 14, 13

Page 5: Rails Sojourn: One Man's Journey - Wicked Good Ruby Conference 2013

CONFESSION

Monday, October 14, 13

Page 6: Rails Sojourn: One Man's Journey - Wicked Good Ruby Conference 2013

OK MIKE, WE GET IT. YOU HAVE SELF ESTEEM ISSUES.

So what is this presentation about?

Monday, October 14, 13

Page 7: Rails Sojourn: One Man's Journey - Wicked Good Ruby Conference 2013

So I’ve worked on some decently “big” Rails apps

Monday, October 14, 13

Page 8: Rails Sojourn: One Man's Journey - Wicked Good Ruby Conference 2013

FAT MODELS

Monday, October 14, 13

Page 9: Rails Sojourn: One Man's Journey - Wicked Good Ruby Conference 2013

MASSIVE CONTROLLERSMonday, October 14, 13

Page 10: Rails Sojourn: One Man's Journey - Wicked Good Ruby Conference 2013

VIEWS WITH

(CONFUSING) LOGIC

IN THEM

Monday, October 14, 13

Page 11: Rails Sojourn: One Man's Journey - Wicked Good Ruby Conference 2013

STUFF HAPPENS

Monday, October 14, 13

Page 12: Rails Sojourn: One Man's Journey - Wicked Good Ruby Conference 2013

GOOD NEWS:This presentation isn’t a complain-fest about Rails

Monday, October 14, 13

Page 13: Rails Sojourn: One Man's Journey - Wicked Good Ruby Conference 2013

I work here:

(we’re kinda awesome)Monday, October 14, 13

Page 14: Rails Sojourn: One Man's Journey - Wicked Good Ruby Conference 2013

But I used to work here:

Monday, October 14, 13

Page 15: Rails Sojourn: One Man's Journey - Wicked Good Ruby Conference 2013

(NEED A BULLPEN)

Monday, October 14, 13

Page 16: Rails Sojourn: One Man's Journey - Wicked Good Ruby Conference 2013

INCUBATIONMONTH

Monday, October 14, 13

Page 17: Rails Sojourn: One Man's Journey - Wicked Good Ruby Conference 2013

LIKE CHRISTMAS MORNING!

Monday, October 14, 13

Page 18: Rails Sojourn: One Man's Journey - Wicked Good Ruby Conference 2013

WE SHOULD USE

THIS TIME TO EXPLORE!

Monday, October 14, 13

Page 19: Rails Sojourn: One Man's Journey - Wicked Good Ruby Conference 2013

LET’S BUILD AN APP!It’ll be one of those

new-fangledsingle page whizz-

bang Javascript MVC thingies!

Monday, October 14, 13

Page 20: Rails Sojourn: One Man's Journey - Wicked Good Ruby Conference 2013

WHAT TO DO?

Monday, October 14, 13

Page 21: Rails Sojourn: One Man's Journey - Wicked Good Ruby Conference 2013

WHAT TO DO?

Monday, October 14, 13

Page 22: Rails Sojourn: One Man's Journey - Wicked Good Ruby Conference 2013

WHAT TO DO?

Monday, October 14, 13

Page 23: Rails Sojourn: One Man's Journey - Wicked Good Ruby Conference 2013

BACK END CRITERIA•Had to be Ruby•Building RESTful API•Had to be easily deployed•Want “lightweight”•Had to be actively developed•Couldn’t be Rails. Just ‘cuz.

Monday, October 14, 13

Page 24: Rails Sojourn: One Man's Journey - Wicked Good Ruby Conference 2013

Monday, October 14, 13

Page 25: Rails Sojourn: One Man's Journey - Wicked Good Ruby Conference 2013

FRONT END CRITERIA

•Active Development•Strategic choice for company•Well documented•Stable API

(Not gonna talk a whole lot about these)Monday, October 14, 13

Page 26: Rails Sojourn: One Man's Journey - Wicked Good Ruby Conference 2013

FRONTEND

(Not gonna talk a whole lot about these)Monday, October 14, 13

Page 27: Rails Sojourn: One Man's Journey - Wicked Good Ruby Conference 2013

ARCHITECTURE

User Application

Amazon SQS (Queueing Service)

Static Single-Page Javascript Front End

Happy User

Notifications

Client Gem

Worker Process

Worker Process

Collector

SQLDB

Collector

API ServerAPI Server

Monday, October 14, 13

Page 28: Rails Sojourn: One Man's Journey - Wicked Good Ruby Conference 2013

FOCUS ON

CollectorCollector API ServerAPI Server

THE “RUBY” PARTS

Monday, October 14, 13

Page 29: Rails Sojourn: One Man's Journey - Wicked Good Ruby Conference 2013

HMM...require  'sinatra'

get  '/hi'  do    "Hello  World!"end

$  ruby  hi.rbMonday, October 14, 13

Page 30: Rails Sojourn: One Man's Journey - Wicked Good Ruby Conference 2013

HMM...

$  lsapp.rb$

Monday, October 14, 13

Page 31: Rails Sojourn: One Man's Journey - Wicked Good Ruby Conference 2013

Monday, October 14, 13

Page 32: Rails Sojourn: One Man's Journey - Wicked Good Ruby Conference 2013

GOOD NEWS:This presentation isn’t a How-To

session on Sinatra

Monday, October 14, 13

Page 33: Rails Sojourn: One Man's Journey - Wicked Good Ruby Conference 2013

SETTLED ON THISGemfileGemfile.lockProcfileREADME.mdRakefileapp.rbconfig/config.rulog/middlewares/routes/services/spec/templates/

Monday, October 14, 13

Page 34: Rails Sojourn: One Man's Journey - Wicked Good Ruby Conference 2013

INIT.RB PATTERN

Monday, October 14, 13

Page 35: Rails Sojourn: One Man's Journey - Wicked Good Ruby Conference 2013

CONFIG AND INITIALIZERS

Monday, October 14, 13

Page 36: Rails Sojourn: One Man's Journey - Wicked Good Ruby Conference 2013

THIS SERVED US PRETTY WELL.

Monday, October 14, 13

Page 37: Rails Sojourn: One Man's Journey - Wicked Good Ruby Conference 2013

ASIDE: MONKLearned about this project

after the fact.

Website down?

http://monkrb.comMonday, October 14, 13

Page 38: Rails Sojourn: One Man's Journey - Wicked Good Ruby Conference 2013

WAIT, WHERE ARE THE MODELS?

Monday, October 14, 13

Page 39: Rails Sojourn: One Man's Journey - Wicked Good Ruby Conference 2013

ORM

Monday, October 14, 13

Page 40: Rails Sojourn: One Man's Journey - Wicked Good Ruby Conference 2013

ORMWe tried three different ones.

Models were in their own gem.

Monday, October 14, 13

Page 41: Rails Sojourn: One Man's Journey - Wicked Good Ruby Conference 2013

DATAMAPPERRan into issues.

1.x kind of a ghost town.

Monday, October 14, 13

Page 42: Rails Sojourn: One Man's Journey - Wicked Good Ruby Conference 2013

Monday, October 14, 13

Page 43: Rails Sojourn: One Man's Journey - Wicked Good Ruby Conference 2013

OPEN SOURCE

Monday, October 14, 13

Page 44: Rails Sojourn: One Man's Journey - Wicked Good Ruby Conference 2013

OPEN SOURCEYou can, you know, actually

read the source when you get stuck.

Monday, October 14, 13

Page 45: Rails Sojourn: One Man's Journey - Wicked Good Ruby Conference 2013

ONE OF THE BIGGEST THINGS

I LEARNED!•I always had been intimidated by

complexity Rails’ source.

•Intimidated by size and talent of community.

•Hadn’t run into trouble with Rails, no need to look at the source.

Monday, October 14, 13

Page 46: Rails Sojourn: One Man's Journey - Wicked Good Ruby Conference 2013

bundle  open  <gem  name>

Monday, October 14, 13

Page 47: Rails Sojourn: One Man's Journey - Wicked Good Ruby Conference 2013

DON’T BE AFRAID.

LESSON #1

Monday, October 14, 13

Page 48: Rails Sojourn: One Man's Journey - Wicked Good Ruby Conference 2013

SEQUELWeird (concurrency?) problem we just couldn’t nail down.

Probably wasn’t Sequel, probably was us.Running out of time so...

Monday, October 14, 13

Page 49: Rails Sojourn: One Man's Journey - Wicked Good Ruby Conference 2013

ACTIVERECORDWe swallowed our pride.

Monday, October 14, 13

Page 50: Rails Sojourn: One Man's Journey - Wicked Good Ruby Conference 2013

PUTTING THE MODELS INTO

THEIR OWN GEM SAVED OUR

BACON.Monday, October 14, 13

Page 51: Rails Sojourn: One Man's Journey - Wicked Good Ruby Conference 2013

ISOLATE YOUR APP FROM YOUR

LIBRARY CHOICES.

LESSON #2

Monday, October 14, 13

Page 52: Rails Sojourn: One Man's Journey - Wicked Good Ruby Conference 2013

WHAT IS RACK?Monday, October 14, 13

Page 53: Rails Sojourn: One Man's Journey - Wicked Good Ruby Conference 2013

“A Rack application is an Ruby object (not a class) that responds to call. It takes exactly one argument, the environment and returns an Array of exactly three values: The status, the headers, and the body.” - Rack API docs

Monday, October 14, 13

Page 54: Rails Sojourn: One Man's Journey - Wicked Good Ruby Conference 2013

“A Rack application is an Ruby object (not a class) that responds to call. It takes exactly one argument, the environment and returns an Array of exactly three values: The status, the headers, and the body.” - Rack API docs

require  'rubygems'require  'rack'

class  HelloWorld    def  call(env)        [200,  {"Content-­‐Type"  =>  "text/html"},  "Hello  Rack!"]    endend

Rack::Handler::Mongrel.run  HelloWorld.new,  :port  =>  9292

Monday, October 14, 13

Page 55: Rails Sojourn: One Man's Journey - Wicked Good Ruby Conference 2013

MIDDLEWAREMonday, October 14, 13

Page 56: Rails Sojourn: One Man's Journey - Wicked Good Ruby Conference 2013

SECURITYMonday, October 14, 13

Page 57: Rails Sojourn: One Man's Journey - Wicked Good Ruby Conference 2013

• Rack::Attack - middleware to do whitelisting, blacklisting, throttling.

• Rack::Protection - middleware that handles a bunch of attack vectors (IP Spoofing, Path Traversal, Session Hijacking, others).

• Omniauth::Identity - User authentication

Monday, October 14, 13

Page 58: Rails Sojourn: One Man's Journey - Wicked Good Ruby Conference 2013

SERIALIZATION

Monday, October 14, 13

Page 59: Rails Sojourn: One Man's Journey - Wicked Good Ruby Conference 2013

SERIALIZATION

• achiu/rack-parser - I was surprised to learn that converting JSON docs to Rack parameters wasn’t automatic.

• HashWithIndifferentAccess - Don’t expect your parameter names to be symbolized for you.

Monday, October 14, 13

Page 60: Rails Sojourn: One Man's Journey - Wicked Good Ruby Conference 2013

SESSION COOKIESRack::Session::Cookie

Monday, October 14, 13

Page 61: Rails Sojourn: One Man's Journey - Wicked Good Ruby Conference 2013

WE EVEN WROTE OUR OWN

MIDDLEWARE!

HTTP status handling for common errors

Monday, October 14, 13

Page 62: Rails Sojourn: One Man's Journey - Wicked Good Ruby Conference 2013

class  ErrorMiddleware    def  initialize(app,  options  =  {})        @app  =  app    end        def  call(env)        dup._call(env)    end

   def  _call(env)        @app.call  env    rescue  Exception  =>  e        logger.error  "-­‐-­‐-­‐  rescued  #{e.inspect}  at  #{Time.now}  -­‐-­‐-­‐"        e.backtrace.each  do  |line|            logger.error  line        end

       handler  =  ExceptionHandler.new(e)        Rack::Response.new(handler.body,  handler.status,  {}).finish    endend

Monday, October 14, 13

Page 63: Rails Sojourn: One Man's Journey - Wicked Good Ruby Conference 2013

ExceptionHandler.register(    "CloudshineData::UniqueConstraintViolation"  =>  {        body:  {errors:  ["Already  taken"]}.to_json,        status:  422    })

ExceptionHandler.register(    "CloudshineData::Unauthorized"  =>  {status:  401,  body:  "Unauthorized"})

ExceptionHandler.register(    "CloudshineData::RecordNotFound"  =>  {        body:  {errors:  ["Resource  not  found."]}.to_json,        status:  404    })

ExceptionHandler.register("CloudshineData::ValidationFailed"  =>  HandlerWithMessage)

ExceptionHandler.register("Cloudshine::MissingParameter"  =>  HandlerWithMessage)

INITIALIZER

Monday, October 14, 13

Page 64: Rails Sojourn: One Man's Journey - Wicked Good Ruby Conference 2013

class  ExceptionHandler    HANDLERS  =  {}    attr_accessor  :exception

   def  self.register(handler={})        HANDLERS.merge!(handler)    end

   def  initialize(exception)        @exception  =  exception        @handler_map  =  HANDLERS        @handler_map.default  =  {body:  {errors:  ["Server  error"]}.to_json,  status:  500}    end

   def  handler        return  @handler  if  @handler        logger.info  "using  #{handler_map[@exception.class.to_s]}  to  handle”        logger.info  "  a  #{@exception.class.to_s}  exception."        handler  =  handler_map[@exception.class.to_s]        @handler  =  handler.is_a?(Class)  ?  handler.new(@exception)  :  OpenStruct.new(handler)    end

   def  status;  handler.status;  end    def  body;  handler.body;  end

   private    attr_accessor  :handler_mapend

Monday, October 14, 13

Page 65: Rails Sojourn: One Man's Journey - Wicked Good Ruby Conference 2013

MIDDLEWARE IS EASY!

LESSON #3

Monday, October 14, 13

Page 66: Rails Sojourn: One Man's Journey - Wicked Good Ruby Conference 2013

TOOLS

Monday, October 14, 13

Page 67: Rails Sojourn: One Man's Journey - Wicked Good Ruby Conference 2013

ARCHITECTURE

User Application

Amazon SQS (Queueing Service)

Static Single-Page Javascript Front End

Happy User

Notifications

Client Gem

Worker Process

Worker Process

Collector

SQLDB

Collector

API ServerAPI Server

Monday, October 14, 13

Page 68: Rails Sojourn: One Man's Journey - Wicked Good Ruby Conference 2013

CODE IS SPREAD OVER EIGHT

REPOSITORIES

Minimum of four separate applications just to run the system.

Monday, October 14, 13

Page 69: Rails Sojourn: One Man's Journey - Wicked Good Ruby Conference 2013

VAGRANT

Monday, October 14, 13

Page 70: Rails Sojourn: One Man's Journey - Wicked Good Ruby Conference 2013

VAGRANTStill doesn’t help w/ the nuisance of having to commit code into multiple places to make one feature change.

Monday, October 14, 13

Page 71: Rails Sojourn: One Man's Journey - Wicked Good Ruby Conference 2013

VAGRANTIf I had to do it over again, I’d

probably keep one repo/app for the server-side components and deploy

it differently by task.Monday, October 14, 13

Page 72: Rails Sojourn: One Man's Journey - Wicked Good Ruby Conference 2013

OTHER HANDY TOOLS

Monday, October 14, 13

Page 73: Rails Sojourn: One Man's Journey - Wicked Good Ruby Conference 2013

RAILS CONSOLEMonday, October 14, 13

Page 74: Rails Sojourn: One Man's Journey - Wicked Good Ruby Conference 2013

RAILS CONSOLEMissed it for a while.

Monday, October 14, 13

Page 75: Rails Sojourn: One Man's Journey - Wicked Good Ruby Conference 2013

RAILS CONSOLEMissed it for a while.

Then I realized I could just make a silly setup script.

Monday, October 14, 13

Page 76: Rails Sojourn: One Man's Journey - Wicked Good Ruby Conference 2013

RAILS CONSOLEMissed it for a while.

Then I realized I could just make a silly setup script.

It worked just as well and was a lot faster.

Monday, October 14, 13

Page 77: Rails Sojourn: One Man's Journey - Wicked Good Ruby Conference 2013

SILLY SETUP SCRIPTrequire  'bundler'require  'active_record'require  'activeuuid'Bundler.require(:default,:development)ActiveRecord::Base.establish_connection(    :adapter    =>  'mysql2',    :database  =>  'cloudshine_dev',    :username  =>  'root',    :host          =>  'localhost')ActiveUUID::Patches.apply!

Monday, October 14, 13

Page 78: Rails Sojourn: One Man's Journey - Wicked Good Ruby Conference 2013

RERUNMonday, October 14, 13

Page 79: Rails Sojourn: One Man's Journey - Wicked Good Ruby Conference 2013

RERUN

Restarts your server for you when files change in your app’s directory.

Wouldn’t work with pokey old Rails but works great with Sinatra.

Monday, October 14, 13

Page 80: Rails Sojourn: One Man's Journey - Wicked Good Ruby Conference 2013

CORS Issues

Cross Origin Resource Sharing

Monday, October 14, 13

Page 81: Rails Sojourn: One Man's Journey - Wicked Good Ruby Conference 2013

User’s Browser Web Server

HTTP  OPTIONS  http://api.myapp.com/resource

Origin:  http://www.myapp.com

PRE-F

LIGHT

Monday, October 14, 13

Page 82: Rails Sojourn: One Man's Journey - Wicked Good Ruby Conference 2013

200  OK

Access-­‐Control-­‐Allow-­‐Origin:  http://www.myapp.com

User’s Browser Web Server

Monday, October 14, 13

Page 83: Rails Sojourn: One Man's Journey - Wicked Good Ruby Conference 2013

HTTP  GET  http://api.myapp.com/resource

Origin:  http://www.myapp.com

User’s Browser Web Server

Monday, October 14, 13

Page 84: Rails Sojourn: One Man's Journey - Wicked Good Ruby Conference 2013

CORS SupportFirefox: 3.5+Chrome: 3+Safari: 4+

Opera: 12+IE: 10+

Monday, October 14, 13

Page 85: Rails Sojourn: One Man's Journey - Wicked Good Ruby Conference 2013

CORS IssuesCan’t serve your singlepage app from file:// during development

Can’t go across ports without explicit

permission

Monday, October 14, 13

Page 86: Rails Sojourn: One Man's Journey - Wicked Good Ruby Conference 2013

CORS Issues

Did all of this with (you guessed it) middleware!

github.com/cyu/rack-cors

Monday, October 14, 13

Page 87: Rails Sojourn: One Man's Journey - Wicked Good Ruby Conference 2013

SUMMARY•Don’t be afraid to look at the source code

of your libraries.•Isolate your app from libraries•Middleware is easy!•There are lots of cool tools out there. Learn

about them.•Figure out your strategy for dealing w/

cross origin requests right away.

Monday, October 14, 13

Page 88: Rails Sojourn: One Man's Journey - Wicked Good Ruby Conference 2013

SPENDING TIME AWAY FROM RAILS DE-MYSTIFIED IT FOR ME AND MADE ME

MORE COMFORTABLE WITH RUBY.

Monday, October 14, 13

Page 89: Rails Sojourn: One Man's Journey - Wicked Good Ruby Conference 2013

SPENDING TIME AWAY FROM RAILS DE-MYSTIFIED IT FOR ME AND MADE ME

MORE COMFORTABLE WITH RUBY.

It was totally worth it.

Monday, October 14, 13

Page 90: Rails Sojourn: One Man's Journey - Wicked Good Ruby Conference 2013

HOWEVER...

If I were starting all over again,I probably would just use

Rails API.

Monday, October 14, 13

Page 91: Rails Sojourn: One Man's Journey - Wicked Good Ruby Conference 2013

Monday, October 14, 13

Page 92: Rails Sojourn: One Man's Journey - Wicked Good Ruby Conference 2013

@mdesjardins

github.com/mdesjardins

[email protected]

Monday, October 14, 13

Page 93: Rails Sojourn: One Man's Journey - Wicked Good Ruby Conference 2013

FIN.Monday, October 14, 13

Page 94: Rails Sojourn: One Man's Journey - Wicked Good Ruby Conference 2013

PHOTO CREDITSLobster on Slide 2: Creative Commons © Man Pikin (http://www.flickr.com/photos/musicamang/)

Priest on Slide 3: © Anyka, Licensed from Fotolia.com, All Rights Reserved

Giant NES Controller on Slide 8: Creative Commons © Pop Culture Geek (http://www.flickr.com/photos/popculturegeek/)

Boston Construction Road Sign on Slide 9: Creative Commons © NNECAPA (http://www.flickr.com/photos/nnecapa/)

Bird Poop on Slide 10: Creative Commons © Chris Smith Ronnie Shumate “My Favorite Pet Sitter” (http://www.flickr.com/photos/myfavoritepetsitter/)

Fenway Bullpen on Slide 15: Creative Commons © BuzzFarmers “Red Sox Game at Fenway Park.” (http://www.flickr.com/photos/buzzfarmers/)

Alien Incubator on Slide 16: Creative Commons © Steve Jurvetson “alien incubator” (http://www.flickr.com/photos/jurvetson/)

Christmas Morning on Slide 17: Creative Commons © John Lemieux “Nikon Christmas” (http://www.flickr.com/photos/newdimensionfilms/)

Segway on Slide 42: Creative Commons © Wesley Fryer “Darth Vader on a segway in the Edmond 4th of July Parade” (http://www.flickr.com/photos/wfryer)

Bacon on Slide 49: Creative Commons © Shawn Zamecheck “Bacon” (http://www.flickr.com/photos/shawnzam/)

Rack of Lamb on Slide 51: Creative Commons © Waferboard “rack of lamb presentation II” (http://www.flickr.com/photos/waferboard/)

Rainbow Cake on Slide 54: Creative Commons © Janine and Jim Eden “Rainbow Cake” (http://www.flickr.com/photos/edenpictures/)

Security Cameras on Slide 55: Creative Commons © Jake Setlak “Security” (http://www.flickr.com/photos/pylbug/)

Cookies on Slide 59: Creative Commons © Jeramey Jannene “Cookies” (http://www.flickr.com/photos/compujeramey/)

Tool Chest on Slide 66: Creative Commons © El Cajon Yacht Club “tool chest” (http://www.flickr.com/photos/el_cajon_yacht_club/)

Console on Slide 73: Creative Commons © Cliff “Console, Countdown and Monitor“ (http://www.flickr.com/photos/nostri-imago/)

Apple Cores Slides 80-85: Creative Commons © Roger Karlsson “red apple core two days” (http://www.flickr.com/photos/free-photos/)

Mosaic 3.5” Floppy Slides 81-83: Creative Commons © Bill Rawlinson “plug-n-play-mosaic” (http://www.flickr.com/photos/thefinalcut/)

Mainframe Slides 81-83: Creative Commons © Don DeBold “NEC 2203 Mainframe Computer” (http://www.flickr.com/photos/ddebold/)

Creative Commons images licensed under the CC 2.0 Attribution License.

Monday, October 14, 13