Frozen Rails Slides

Post on 06-Sep-2014

5.665 views 0 download

Tags:

description

 

Transcript of Frozen Rails Slides

Rails 3: With a Vengeance

Friday, May 7, 2010

Friday, May 7, 2010

Friday, May 7, 2010

Rails 3: With a Vengeance

Friday, May 7, 2010

Friday, May 7, 2010

New talk title:

Friday, May 7, 2010

Rails 3: Tasty Burgers

DHH introduced Rails 3 at last RailsConf. He likes whoppers. I actually hate burger king entirely. I’m not sure how anybody can eat there. But that’s OK, because I can make my own rails burger the way I like

Friday, May 7, 2010

Friday, May 7, 2010

Skill

Friday, May 7, 2010

A lot like Rails 2.3We tried really hard to not break any 2.x APIs unless it was really deemed necessary or a big win.

Friday, May 7, 2010

But not really...

Only surface level stuff is the same. A lot under the hood has changed and there are a lot more features. I obviously can’t cover everything in depth in an hour, so I’m going to gloss over a lot and you can all look into details later.

Friday, May 7, 2010

Quick Refresher

What hasn’t changed

Friday, May 7, 2010

MVC

Friday, May 7, 2010

REST

Friday, May 7, 2010

Resources

The router / controller / ActiveRecord model is still optimized for organizing your application in terms of Resources

Friday, May 7, 2010

Controllers

Friday, May 7, 2010

ActiveRecord

Some changes (Arel, query api - Not going to really cover this)General ideas are the sameassociationsActiveRecord pattern

Friday, May 7, 2010

Migrations

Friday, May 7, 2010

So, what did change?

Friday, May 7, 2010

File structure

There were some tweaks to the default File structure, mostly in the config directory.

This is what you get when you generate a new Rails 3 app

One big thing about Rails 3 is that the app file structure is not sacred, it’s just a convention, not obligation

Friday, May 7, 2010

config.ru

# This file is used by Rack-based servers# to start the application.

require ::File.expand_path( '../config/environment', __FILE__)run AwesomeBlog::Application

Rails 3 is pure Rack. When you start an app, it evaluates config.ru, which is a rack convention. If this file is there, all rack compatible rack servers know what to do.Could put middleware or whatever here (could even put a full Rails app in this one file).

Who doesn’t know what Rack is?

Could put middleware or whatever here (could even put a full Rails app in this one file).

Friday, May 7, 2010

config.ru

# This file is used by Rack-based servers# to start the application.

require ::File.expand_path( '../config/environment', __FILE__)run AwesomeBlog::Application

That’s specifically the line that rack is looking for.

The constant is a Rack app that encapsulates everything related to the entire rails application that we’re building

Friday, May 7, 2010

config/application.rb

require File.expand_path('../boot', __FILE__)require 'rails/all'

Bundler.require(:default, Rails.env) if defined?(Bundler)

module AwesomeBlog class Application < Rails::Application config.encoding = "utf-8" config.filter_parameters += [:password] endend

This is the file that defines the application object from the last slide.

Let’s look at some key components

Friday, May 7, 2010

config/application.rb

require File.expand_path('../boot', __FILE__)require 'rails/all'

Bundler.require(:default, Rails.env) if defined?(Bundler)

module AwesomeBlog class Application < Rails::Application config.encoding = "utf-8" config.filter_parameters += [:password] endend

Friday, May 7, 2010

config/application.rb

require File.expand_path('../boot', __FILE__)require 'rails/all'

Bundler.require(:default, Rails.env) if defined?(Bundler)

module AwesomeBlog class Application < Rails::Application config.encoding = "utf-8" config.filter_parameters += [:password] endend

Friday, May 7, 2010

config/application.rb

require File.expand_path('../boot', __FILE__)require 'rails/all'

Bundler.require(:default, Rails.env) if defined?(Bundler)

module AwesomeBlog class Application < Rails::Application config.encoding = "utf-8" config.filter_parameters += [:password] endend

A Rack App!

Friday, May 7, 2010

Application ObjectOne day, we’ll have many application objects in one process.

Ruby summer of code project to get this done.

Contains all application specific information. Takes the “in the sky” constants / globals that were needed for a rails 2.3 application and encapsulates them.

Routes, Config , Middleware, Initializers

Friday, May 7, 2010

config/application.rb

require File.expand_path('../boot', __FILE__)require 'rails/all'

Bundler.require(:default, Rails.env) if defined?(Bundler)

module AwesomeBlog class Application < Rails::Application config.encoding = "utf-8" config.filter_parameters += [:password] endend

Friday, May 7, 2010

config/boot.rb

require 'rubygems'

# Set up gems listed in the Gemfile.gemfile = File.expand_path('../../Gemfile', __FILE__)begin ENV['BUNDLE_GEMFILE'] = gemfile require 'bundler' Bundler.setuprescue Bundler::GemNotFound => e STDERR.puts e.message STDERR.puts "Try running `bundle install`." exit!end if File.exist?(gemfile)

Friday, May 7, 2010

config/boot.rb

require 'bundler' Bundler.setup

Friday, May 7, 2010

Bundler is a tool we built to manage gem dependencies. As it turns out, as rails applications grow, dependencies become painful to deal with.

Many years in the making. Many iterations. It grew out of projects that had many complicate dependencies and it was basically impossible to deal with it all by hand

Friday, May 7, 2010

Gemfile

source 'http://rubygems.org'

gem 'rails', '3.0.0.beta3'gem 'sqlite3-ruby', :require => 'sqlite3'

It all starts here. This file is located at the root of the application.

All gem dependencies will be listed here. So far our app is small, so we only depend on rails itself (note the version is the one that we are currently working with) and also we have a dependency on sqlite since that’s the database that we’re using.

Friday, May 7, 2010

$ bundle install

Step two is to run the “bundle install” command.

* Checks gems already on system* Downloads what is missing

Friday, May 7, 2010

No step 3

Friday, May 7, 2010

Wins:

What are the major wins that we get from using bundler?

Friday, May 7, 2010

Easy to update dependencies

Dependencies in applications will evolve a lot throughout the life of an application

Ruby is maturing. There are a LOT of gems out there that you’ll be wanting to use. Bundler makes doing it easy.

Friday, May 7, 2010

Gemfile

source 'http://rubygems.org'

gem 'rails', '3.0.0.beta3'gem 'sqlite3-ruby', :require => 'sqlite3'

What happens if you want to update your application to the latest version of rails?

Friday, May 7, 2010

Gemfile

source 'http://rubygems.org'

gem 'rails', '3.0.0'gem 'sqlite3-ruby', :require => 'sqlite3'

You’re done. All child dependencies will be handled for you.

The same goes if you want to roll back to a previous version. Just change the Gemfile

Friday, May 7, 2010

Isolation

You know all your dependencies are accounted for and you won’t be surprised when you deploy.

Bundler does not let you use a gem if it is not listed in the Gemfile. So, you can’t accidentally forget to install a gem on the server when you deploy.

Friday, May 7, 2010

Sharing

Your Gemfile accounts for all gems. You share your app with other developers. They run `bundle install` and they’re good to go.

Bundler tracks all child dependencies as well as top level app dependencies

Come back to a project 3 months later. What version of UUID was I using? (yeah, that broke deploys) Nokogiri?

Designers

Friday, May 7, 2010

No conflicts

Anybody ever hit the “can’t activate gem foo, already activated foo at another version error”?

Friday, May 7, 2010

Without Bundler

Friday, May 7, 2010

Friday, May 7, 2010

The Solution!Step 1) VendorRails + Rack

Friday, May 7, 2010

The Solution!Step 1) Modify the Rails source

Friday, May 7, 2010

While we’re on the topic of picard....

Friday, May 7, 2010

Friday, May 7, 2010

Friday, May 7, 2010

http://gembundler.com

Friday, May 7, 2010

Unobtrusive Javascript

Friday, May 7, 2010

Helpers do not generate JS anymore

In Rails 2.3, all view helpers that required JS would spew out a whole bunch of Prototype specific javascript inline.

This is bad.

Friday, May 7, 2010

<%= link_to "hello", hello_path, :remote => true %>

<a href="/hello" data-remote="true">hello</a>

Rails 3.0 helpers will now only output HTML. All required information will be added to the HTML tags via data-*

Custom data-* attributes were added in HTML5, but they work in all old and busted (IE 6).

Friday, May 7, 2010

public/javascripts/rails.js

$(document.body).observe("click", function(event) { // .... var element = event.findElement( "a[data-remote]"); if (element) { handleRemote(element); event.stop(); return true; } // ....});

The javascript that handles all the data-* attributes is in rails.js

Friday, May 7, 2010

Using jQuery?http://github.com/rails/jquery-ujs

Rails will ship with the Prototype driver, but you can just drop in the jquery driver at public/javascripts/rails.js

We maintain it and it’s on github at the URL.

You can finally easily completely rid your Rails app of all Prototype

Who uses jQuery?

Friday, May 7, 2010

public/javascripts/rails.js

$('a[data-remote],input[data-remote]').live('click', function (e) { $(this).callRemote(); e.preventDefault();});

This is the code that is in the jQuery rails.js driver

Friday, May 7, 2010

Pick your JS framework when you write JS, not when you generate

your Rails app.

Other wins too.

Friday, May 7, 2010

Customizable

Just JS events being triggered. You can easily replace specific default behavior.

There are events that are triggered that you can bind to. ajax:before, ajax:after, etc...

Friday, May 7, 2010

Everything is a “plugin”

Rails is like a toolkit to build rails. Think about it.

Friday, May 7, 2010

ActiveRecord?

Friday, May 7, 2010

Plugin!

Friday, May 7, 2010

ActionController?

Friday, May 7, 2010

Plugin!

Friday, May 7, 2010

TestUnit

Friday, May 7, 2010

Plugin!

Friday, May 7, 2010

ActiveResource?

Friday, May 7, 2010

...

Friday, May 7, 2010

You can build plugins too.

Friday, May 7, 2010

Railtie

Railtie is a class that integrates a library with rails.

Look at how ActiveRecord does it. Look at how everything else does it.

When we built Rails 3, we didn’t add hook points for all these other libraries after the fact. We made hooks for ourselves to use, which has the nice side effect of other libraries being able to use them.

RSpec, DataMapper, HAML, etc... all use the same hooks that Rails uses

Friday, May 7, 2010

Configuration

Rake Tasks

Generator Overrides

Initializers

You actually rarely need a Railtie to integrate with Rails. Railties are for a few specific things.

Friday, May 7, 2010

Configuration

Rake Tasks

Generator Overrides

Initializers

Provide configuration opportunities to Rails applications

config.active_record in config/application.rb

If you want to provide default config values, you need a Railtie

Friday, May 7, 2010

Configuration

Rake Tasks

Generator Overrides

Initializers

All ActiveRecord’s rake tasks are in it’s Railtie, which means that when AR isn’t required, the rake tasks go away.

If you want to easily provide Rake tasks to a Rails app, you need a Railtie

Friday, May 7, 2010

Configuration

Rake Tasks

Generator Overrides

Initializers

If you want to hook in to:* rails generate controller Foo* rails generate model Foo

you need a Railtie. RSpec uses this to provide the same level of integration that TestUnit gets

Friday, May 7, 2010

Configuration

Rake Tasks

Generator Overrides

Initializers

If you want to hook into the initialization cycle of a Rails application, you’ll need a Railtie

Friday, May 7, 2010

HTML escaping

Friday, May 7, 2010

<p> <%= h @comment.title %> (by <%= h @comment.author.username %>)</p>

<%= simple_format h(@comment.body) %>

Rails 2.3

This is what a view might have looked in Rails 2.3

Friday, May 7, 2010

Rails 2.3

If you forget one spot, you’re site gets hacked

... I’m sure everybody here has missed at least 1 spot to escape

<p> <%= h @comment.title %> (by <%= h @comment.author.username %>)</p>

<%= simple_format h(@comment.body) %>

Friday, May 7, 2010

<p> <%= @comment.title %> (by <%= @comment.author.username %>)</p>

<%= simple_format(@comment.body) %>

Rails 3.0

New! No more pesky h()

Now, you don’t have to worry about escaping anything anymore. Rails does it for you.

Friday, May 7, 2010

XSS Protection by default

Friday, May 7, 2010

def escaped(str) strend

def not_escaped(str) str.html_safeend

app/helpers/application_helper.rb

Simply returning a string a string will be escaped.

If you don’t want a string to be escaped, you just mark it as html_safe and it won’t be modified by Rails.

Friday, May 7, 2010

Block helpers

Friday, May 7, 2010

<% form_for @post do |f| %> <%= f.text_field :title %><% end %>

<% box do %> <p>Hello World!</p><% end %>

Rails 2.3

This is what block helpers might look like in 2.3

Friday, May 7, 2010

def box(&block) content = "<div class='box'>" << capture(&block) << "</div>"

if block_called_from_erb? concat(content) else content endend

Rails 2.3

This is the implementation.

I’m not even going to really talk about this, Just notice that it’s crazy

Most of this is needed to make the helper work in and outside of ERB.

Friday, May 7, 2010

<% form_for @post do |f| %> <%= f.text_field :title %><% end %>

<% box do %> <p>Hello World!</p><% end %>

Rails 2.3

Outputs method’s return value

Ignores method’s return value

The reason why you need the craziness is because of how ERB works.

Friday, May 7, 2010

Rails 3.0

<%= form_for @post do |f| %> <%= f.text_field :title %><% end %>

<%= box do %> <p>Hello World!</p><% end %>

In Rails 3.0 block helpers have become consistent with ERB.

form_for will actually output content to the view, aka, the form tags. So, now you use %=

The same goes for custom block helpers

Friday, May 7, 2010

def box(&block) "<div class='box'>" \ "#{capture(&block)}" \ "</div>"end

Rails 3.0

All you do now for block helpers is return the string that you want outputted to the view.

Block helpers aren’t special anymore. They work the same inside and outside ERB

Friday, May 7, 2010

def box(&block) "<div class='box'>" \ "#{capture(&block)}" \ "</div>".html_safeend

Rails 3.0

Friday, May 7, 2010

Router

Massive API overhaul.

Friday, May 7, 2010

Old DSL still works, just deprecated.

You don’t have to rush to update your route file to get on Rails 3.0

The old DSL will probably stop working in Rails 3.1 or 3.2, but you have time before that happens.

Friday, May 7, 2010

Matching

map.connect "/posts", :controller => :posts, :action => :index

Friday, May 7, 2010

Matching

map.connect "/posts", :controller => :posts, :action => :index

match "/posts" => "posts#index"

posts#index is short hand for specifying the controller and action. It’s just much easier to write.

Friday, May 7, 2010

Optional Segments

match "/posts(/:page)" => "posts#index"

Will match a request to /posts, and a request to /posts/5

if page is not there, params[:page] will be nil, if it is present in the request, the param will be set.

Friday, May 7, 2010

Defaults

match "/posts(/:page)" => "posts#index",:defaults => { :page => 1 }

You can specify default parameters. If the page segment is not in the Request, params[:page] will be set to 1

Friday, May 7, 2010

Named Routes

match "/posts(/:page)" => "posts#index",:defaults => { :page => 1 }, :as => "posts"

The same helpers are available. * posts_path * posts_url

Friday, May 7, 2010

ScopesLet’s you set the same options to a group of routes.

Almost anything can be scoped.

Friday, May 7, 2010

Path Scopes

scope :path => "/admin" do match "/posts" => "posts#index" match "/users" => "users#index"end

/admin/posts

Friday, May 7, 2010

Path Scopes

scope "/admin" do match "/posts" => "posts#index" match "/users" => "users#index"end

Paths are probably the most common item to scope on, so it’s the default.

Friday, May 7, 2010

Module Scope

scope :module => "admin" do match "/posts" => "posts#index" match "/users" => "users#index"end

Routes to Admin::PostsController / Admin::UsersController

Friday, May 7, 2010

Both

namespace "admin" do match "/posts" => "posts#index" match "/users" => "users#index"end

Friday, May 7, 2010

HTTP Methods

Routing by specific HTTP methods

Friday, May 7, 2010

POST Request

match "/posts" => "posts#index",:via => "delete"

Any HTTP method can be used here

Friday, May 7, 2010

Scoping

scope "/posts" do controller :posts do get "/" => :index endend

Friday, May 7, 2010

Scoping

scope "/posts" do controller :posts do get "/" => :index endend

Yet another shorthand

Friday, May 7, 2010

Scoping

scope "/posts" do controller :posts do get "/" => :index endend

get URL

Friday, May 7, 2010

Scoping

get "/posts" => "posts#index"

get / post / post / delete methods are shorthands for :via => “get”

This method can be used anywhere in the routes file

Friday, May 7, 2010

Constraints

Friday, May 7, 2010

Regexp Constraint

get "/:id" => "posts#index", :id => /\d+/

Friday, May 7, 2010

Regexp Constraint

get "/posts" => "posts#mobile", :user_agent => /iPhone/

Constraints on arbitrary methods of Request object.

Will use the “user_agent” method on the Request object

Friday, May 7, 2010

Defaults + Constraints

Friday, May 7, 2010

Constraint + Default

get "/posts" => "posts#mobile", :user_agent => /iPhone/, :mobile => true

How does it not get confused?

If you use a Regex on as the value of the hash, it is a constraint, otherwise, it is a default

Friday, May 7, 2010

Object Constraints

class DubDubConstraint def self.matches?(request) request.host =~ /^(www.)/ # true / false endend

get "/" => "posts#index", :constraints => DubDubConstraint

Any object that responds to matches? can be a router constraint

Friday, May 7, 2010

Rack EverywhereCan be used without AC and only Rack. This is the minimum requirement for “Rails”

Everything that used to be in ActionController that made sense without ActionController. There is a lot, all rack middleware.* Session* Cookies* Router* Flash* etc..

Friday, May 7, 2010

Rack

PostsController.action(:index)

You can get a rack app for any controller action

Friday, May 7, 2010

Routing + Rack

get "/posts" => PostsController.action(:index)

This is what happens behind the scenes in my previous examples

Friday, May 7, 2010

Routing + Rack

get "/posts" => PostsController.action(:index)

Just a Rack app

Friday, May 7, 2010

Routing + Rack

get "/posts" => PostsController.action(:index)

Any Rack app

Friday, May 7, 2010

Routing + Rack

get "/posts" => MySinatraPostsApp

Sinatra app

Friday, May 7, 2010

Routing + Rack

get "/posts" => MyCampingPostsApp

Camping app

Friday, May 7, 2010

Routing + Rack

get "/posts" => MyRamazePostsApp

Ramaze app

Friday, May 7, 2010

Routing + Rack

get "/posts" => MyConstantThatRespondsToCall

Any Rack app

The possibilities are endless

Friday, May 7, 2010

ActionMailer

Friday, May 7, 2010

It’s newMassive API overhaul

I’m out of time

Friday, May 7, 2010

A lot of detailed stuff about what’s new with Rails 3.

* Articles* Blog posts* Screencasts* QAs* Aggregation of other Rails 3 info

Friday, May 7, 2010

http://www.railsdispatch.com/posts/actionmailer

Friday, May 7, 2010

UpgradingI want to mention upgrading really quick

Rails 1.x apps -> 3.0 is really easy (15 minutes)

Rails 2.x is a little bit harder

Friday, May 7, 2010

Step 1) Generate a new appLook at the generated file structure

Friday, May 7, 2010

config.ru

Friday, May 7, 2010

config/*

Friday, May 7, 2010

http://github.com/rails/rails_upgrade* Mail API* Known broken plugins* Helpers

* But all this stuff still will work in rails 3, just will spew out deprecation notices.

It will try to find all deprecated but still working methods as well* Router* AR API* config/** Deprecated constants

Friday, May 7, 2010

Questions?We have 2 other Rails core people here, they can answer

questions too.

Friday, May 7, 2010

Questions?

Email: me@carllerche.com (I accept fan mail)

Twitter : @carllerche (I’m interesting. Really!)

I will tweet the slides. So make sure you are following me.

Friday, May 7, 2010