Pro Yearly is on sale from $80 to $50! »

10 Things You Didn't Know Rails Could do

259f23c3b129f07b0c496b9f0495f07e?s=47 jeg2
April 25, 2012

10 Things You Didn't Know Rails Could do

My talk from RailsConf 2012, in Austin, TX. It's a collection of random tricks you can do with Rails.

259f23c3b129f07b0c496b9f0495f07e?s=128

jeg2

April 25, 2012
Tweet

Transcript

  1. 10 Things You Didn’t Know Rails Could Do

  2. James Edward Gray II I am a regular on the

    Ruby Rogues podcast I have been a Rubyist for eight years now I have written a lot of documentation and code for Ruby, including CSV
  3. 10 Things You Didn’t Know Rails Could Do

  4. 10 Things You Didn’t Know Rails Could Do 4.2⨉ more

    awesome! 42
  5. Rails 3.2.3 Can…

  6. Get You a Hug, Every Friday 1 http://hugfriday.com/

  7. Get You a Hug, Every Friday 1 http://hugfriday.com/

  8. Get You a Hug, Every Friday 1 http://hugfriday.com/

  9. Get You a Hug, Every Friday 1 http://hugfriday.com/

  10. Get You a Hug, Every Friday 1 http://hugfriday.com/

  11. Get You a Hug, Every Friday 1 http://hugfriday.com/

  12. Get You a Hug, Every Friday 1 http://hugfriday.com/

  13. Interfaces Ways to give Rails a hug

  14. Run From a Single File From Avdi Grimm 2

  15. Run From a Single File From Avdi Grimm 2

  16. Run From a Single File From Avdi Grimm 2

  17. Run From a Single File From Avdi Grimm 2

  18. Run From a Single File From Avdi Grimm 2

  19. Remind You of Things 3 class UsersController < ApplicationController #

    TODO: Make it possible to create new users. end
  20. Remind You of Things 3 class UsersController < ApplicationController #

    TODO: Make it possible to create new users. end class User < ActiveRecord::Base # FIXME: Should token really be accessible? attr_accessible :bio, :email, :name, :token end
  21. <%# OPTIMIZE: Paginate this listing. %> <%= render Article.all %>

    Remind You of Things 3 class UsersController < ApplicationController # TODO: Make it possible to create new users. end class User < ActiveRecord::Base # FIXME: Should token really be accessible? attr_accessible :bio, :email, :name, :token end
  22. $ rake notes app/controllers/users_controller.rb: * [ 2] [TODO] Make it

    possible to create new users. app/models/user.rb: * [ 2] [FIXME] Should token really be accessible? app/views/articles/index.html.erb: * [ 1] [OPTIMIZE] Paginate this listing. <%# OPTIMIZE: Paginate this listing. %> <%= render Article.all %> Remind You of Things 3 class UsersController < ApplicationController # TODO: Make it possible to create new users. end class User < ActiveRecord::Base # FIXME: Should token really be accessible? attr_accessible :bio, :email, :name, :token end
  23. $ rake notes app/controllers/users_controller.rb: * [ 2] [TODO] Make it

    possible to create new users. app/models/user.rb: * [ 2] [FIXME] Should token really be accessible? app/views/articles/index.html.erb: * [ 1] [OPTIMIZE] Paginate this listing. <%# OPTIMIZE: Paginate this listing. %> <%= render Article.all %> Remind You of Things 3 class UsersController < ApplicationController # TODO: Make it possible to create new users. end class User < ActiveRecord::Base # FIXME: Should token really be accessible? attr_accessible :bio, :email, :name, :token end
  24. <%# OPTIMIZE: Paginate this listing. %> <%= render Article.all %>

    Remind You of Things 3 class UsersController < ApplicationController # TODO: Make it possible to create new users. end class User < ActiveRecord::Base # FIXME: Should token really be accessible? attr_accessible :bio, :email, :name, :token end $ rake notes:todo app/controllers/users_controller.rb: * [ 2] Make it possible to create new users. $ rake notes:fixme app/models/user.rb: * [ 2] Should token really be accessible?
  25. <%# OPTIMIZE: Paginate this listing. %> <%= render Article.all %>

    Remind You of Things 3 class UsersController < ApplicationController # TODO: Make it possible to create new users. end class User < ActiveRecord::Base # FIXME: Should token really be accessible? attr_accessible :bio, :email, :name, :token end $ rake notes:todo app/controllers/users_controller.rb: * [ 2] Make it possible to create new users. $ rake notes:fixme app/models/user.rb: * [ 2] Should token really be accessible?
  26. Remind You of Things 3 class Article < ActiveRecord::Base belongs_to

    :user attr_accessible :body, :subject # JEG2: Add that code from your blog here. end $ rake notes:custom ANNOTATION=JEG2 app/models/article.rb: * [ 4] Add that Code from your blog here.
  27. Remind You of Things 3 class Article < ActiveRecord::Base belongs_to

    :user attr_accessible :body, :subject # JEG2: Add that code from your blog here. end $ rake notes:custom ANNOTATION=JEG2 app/models/article.rb: * [ 4] Add that Code from your blog here.
  28. Remind You of Things 3

  29. Sandbox Your Console 4 $ rails r 'p [Article, Comment,

    User].map(&:count)' [0, 0, 0] $ rails c --sandbox Loading development environment in sandbox (Rails 3.2.3) Any modifications you make will be rolled back on exit >> jeg2 = User.create!(name: "James Edward Gray II") => #<User id: 1, name: "James Edward Gray II", …> >> article = Article.new(subject: "First Post").tap { |a| a.user = jeg2; a.save! } => #<Article id: 1, user_id: 1, subject: "First Post", …> >> Comment.new(body: "I need to add this.").tap { |c| c.user, c.article = jeg2, article; c.save! } => #<Comment id: 1, user_id: 1, article_id: 1, body: "I need to add this.", …> >> [Article, Comment, User].map(&:count) => [1, 1, 1] >> exit $ rails r 'p [Article, Comment, User].map(&:count)' [0, 0, 0]
  30. Sandbox Your Console 4 $ rails r 'p [Article, Comment,

    User].map(&:count)' [0, 0, 0] $ rails c --sandbox Loading development environment in sandbox (Rails 3.2.3) Any modifications you make will be rolled back on exit >> jeg2 = User.create!(name: "James Edward Gray II") => #<User id: 1, name: "James Edward Gray II", …> >> article = Article.new(subject: "First Post").tap { |a| a.user = jeg2; a.save! } => #<Article id: 1, user_id: 1, subject: "First Post", …> >> Comment.new(body: "I need to add this.").tap { |c| c.user, c.article = jeg2, article; c.save! } => #<Comment id: 1, user_id: 1, article_id: 1, body: "I need to add this.", …> >> [Article, Comment, User].map(&:count) => [1, 1, 1] >> exit $ rails r 'p [Article, Comment, User].map(&:count)' [0, 0, 0]
  31. Sandbox Your Console 4 $ rails r 'p [Article, Comment,

    User].map(&:count)' [0, 0, 0] $ rails c --sandbox Loading development environment in sandbox (Rails 3.2.3) Any modifications you make will be rolled back on exit >> jeg2 = User.create!(name: "James Edward Gray II") => #<User id: 1, name: "James Edward Gray II", …> >> article = Article.new(subject: "First Post").tap { |a| a.user = jeg2; a.save! } => #<Article id: 1, user_id: 1, subject: "First Post", …> >> Comment.new(body: "I need to add this.").tap { |c| c.user, c.article = jeg2, article; c.save! } => #<Comment id: 1, user_id: 1, article_id: 1, body: "I need to add this.", …> >> [Article, Comment, User].map(&:count) => [1, 1, 1] >> exit $ rails r 'p [Article, Comment, User].map(&:count)' [0, 0, 0]
  32. Sandbox Your Console 4 $ rails r 'p [Article, Comment,

    User].map(&:count)' [0, 0, 0] $ rails c --sandbox Loading development environment in sandbox (Rails 3.2.3) Any modifications you make will be rolled back on exit >> jeg2 = User.create!(name: "James Edward Gray II") => #<User id: 1, name: "James Edward Gray II", …> >> article = Article.new(subject: "First Post").tap { |a| a.user = jeg2; a.save! } => #<Article id: 1, user_id: 1, subject: "First Post", …> >> Comment.new(body: "I need to add this.").tap { |c| c.user, c.article = jeg2, article; c.save! } => #<Comment id: 1, user_id: 1, article_id: 1, body: "I need to add this.", …> >> [Article, Comment, User].map(&:count) => [1, 1, 1] >> exit $ rails r 'p [Article, Comment, User].map(&:count)' [0, 0, 0]
  33. Sandbox Your Console 4 $ rails r 'p [Article, Comment,

    User].map(&:count)' [0, 0, 0] $ rails c --sandbox Loading development environment in sandbox (Rails 3.2.3) Any modifications you make will be rolled back on exit >> jeg2 = User.create!(name: "James Edward Gray II") => #<User id: 1, name: "James Edward Gray II", …> >> article = Article.new(subject: "First Post").tap { |a| a.user = jeg2; a.save! } => #<Article id: 1, user_id: 1, subject: "First Post", …> >> Comment.new(body: "I need to add this.").tap { |c| c.user, c.article = jeg2, article; c.save! } => #<Comment id: 1, user_id: 1, article_id: 1, body: "I need to add this.", …> >> [Article, Comment, User].map(&:count) => [1, 1, 1] >> exit $ rails r 'p [Article, Comment, User].map(&:count)' [0, 0, 0]
  34. Run Helper Methods in the Console 5 $ rails c

    Loading development environment (Rails 3.2.3) >> helper.number_to_currency(100) => "$100.00" >> helper.time_ago_in_words(3.days.ago) => "3 days"
  35. Run Helper Methods in the Console 5 $ rails c

    Loading development environment (Rails 3.2.3) >> helper.number_to_currency(100) => "$100.00" >> helper.time_ago_in_words(3.days.ago) => "3 days"
  36. Use Non-WEBrick Servers in Development 6 source 'https://rubygems.org' # ...

    group :development do gem "thin" end $ rails s thin => Booting Thin => Rails 3.2.3 application starting in development on http://0.0.0.0:3000 => Call with -d to detach => Ctrl-C to shutdown server >> Thin web server (v1.3.1 codename Triple Espresso) >> Maximum connections set to 1024 >> Listening on 0.0.0.0:3000, CTRL+C to stop
  37. Use Non-WEBrick Servers in Development 6 source 'https://rubygems.org' # ...

    group :development do gem "thin" end $ rails s thin => Booting Thin => Rails 3.2.3 application starting in development on http://0.0.0.0:3000 => Call with -d to detach => Ctrl-C to shutdown server >> Thin web server (v1.3.1 codename Triple Espresso) >> Maximum connections set to 1024 >> Listening on 0.0.0.0:3000, CTRL+C to stop
  38. Allow You to Tap Into its Configuration From Josh Susser

    7 # lib/custom/railtie.rb module Custom class Railtie < Rails::Railtie config.custom = ActiveSupport::OrderedOptions.new end end
  39. Allow You to Tap Into its Configuration From Josh Susser

    7 # lib/custom/railtie.rb module Custom class Railtie < Rails::Railtie config.custom = ActiveSupport::OrderedOptions.new end end
  40. Allow You to Tap Into its Configuration From Josh Susser

    7 # lib/custom/railtie.rb module Custom class Railtie < Rails::Railtie config.custom = ActiveSupport::OrderedOptions.new end end # config/application.rb # ... require_relative "../lib/custom/railtie" module Blog class Application < Rails::Application # ... config.custom.setting = 42 end end
  41. Allow You to Tap Into its Configuration From Josh Susser

    7 # lib/custom/railtie.rb module Custom class Railtie < Rails::Railtie config.custom = ActiveSupport::OrderedOptions.new end end # config/application.rb # ... require_relative "../lib/custom/railtie" module Blog class Application < Rails::Application # ... config.custom.setting = 42 end end
  42. Allow You to Tap Into its Configuration From Josh Susser

    7 # lib/custom/railtie.rb module Custom class Railtie < Rails::Railtie config.custom = ActiveSupport::OrderedOptions.new end end # config/application.rb # ... require_relative "../lib/custom/railtie" module Blog class Application < Rails::Application # ... config.custom.setting = 42 end end
  43. Keep You Entertained 8

  44. Keep You Entertained 8

  45. The Database A place to store all that drama

  46. Understand Shorthand Migrations $ rails g resource user name:string email:string

    token:string bio:text 9 From José Valim
  47. Understand Shorthand Migrations $ rails g resource user name:string email:string

    token:string bio:text $ rails g resource user name email token:string{6} bio:text 9 From José Valim
  48. Understand Shorthand Migrations $ rails g resource user name:string email:string

    token:string bio:text $ rails g resource user name email token:string{6} bio:text class CreateUsers < ActiveRecord::Migration def change create_table :users do |t| t.string :name t.string :email t.string :token, :limit => 6 t.text :bio t.timestamps end end end 9 From José Valim
  49. Understand Shorthand Migrations $ rails g resource user name:string email:string

    token:string bio:text $ rails g resource user name email token:string{6} bio:text class CreateUsers < ActiveRecord::Migration def change create_table :users do |t| t.string :name t.string :email t.string :token, :limit => 6 t.text :bio t.timestamps end end end 9 From José Valim
  50. Understand Shorthand Migrations $ rails g resource user name:string email:string

    token:string bio:text $ rails g resource user name email token:string{6} bio:text class CreateUsers < ActiveRecord::Migration def change create_table :users do |t| t.string :name t.string :email t.string :token, :limit => 6 t.text :bio t.timestamps end end end 9 From José Valim
  51. Add Indexes to Migrations $ rails g resource user name:index

    email:uniq token:string{6} bio:text 10 From José Valim
  52. Add Indexes to Migrations $ rails g resource user name:index

    email:uniq token:string{6} bio:text class CreateUsers < ActiveRecord::Migration def change create_table :users do |t| t.string :name t.string :email t.string :token, :limit => 6 t.text :bio t.timestamps end add_index :users, :name add_index :users, :email, :unique => true end end 10 From José Valim
  53. Add Indexes to Migrations $ rails g resource user name:index

    email:uniq token:string{6} bio:text class CreateUsers < ActiveRecord::Migration def change create_table :users do |t| t.string :name t.string :email t.string :token, :limit => 6 t.text :bio t.timestamps end add_index :users, :name add_index :users, :email, :unique => true end end 10 From José Valim
  54. Add Indexes to Migrations $ rails g resource user name:index

    email:uniq token:string{6} bio:text class CreateUsers < ActiveRecord::Migration def change create_table :users do |t| t.string :name t.string :email t.string :token, :limit => 6 t.text :bio t.timestamps end add_index :users, :name add_index :users, :email, :unique => true end end 10 From José Valim
  55. Add Associations to a Migration $ rails g resource article

    user:references subject body:text 11 From José Valim
  56. Add Associations to a Migration $ rails g resource article

    user:references subject body:text class CreateArticles < ActiveRecord::Migration def change create_table :articles do |t| t.references :user t.string :subject t.text :body t.timestamps end add_index :articles, :user_id end end class Article < ActiveRecord::Base belongs_to :user attr_accessible :body, :subject end 11 From José Valim
  57. Add Associations to a Migration $ rails g resource article

    user:references subject body:text class CreateArticles < ActiveRecord::Migration def change create_table :articles do |t| t.references :user t.string :subject t.text :body t.timestamps end add_index :articles, :user_id end end class Article < ActiveRecord::Base belongs_to :user attr_accessible :body, :subject end 11 From José Valim
  58. Add Associations to a Migration $ rails g resource article

    user:references subject body:text class CreateArticles < ActiveRecord::Migration def change create_table :articles do |t| t.references :user t.string :subject t.text :body t.timestamps end add_index :articles, :user_id end end class Article < ActiveRecord::Base belongs_to :user attr_accessible :body, :subject end 11 From José Valim
  59. Add Associations to a Migration $ rails g resource article

    user:references subject body:text class CreateArticles < ActiveRecord::Migration def change create_table :articles do |t| t.references :user t.string :subject t.text :body t.timestamps end add_index :articles, :user_id end end class Article < ActiveRecord::Base belongs_to :user attr_accessible :body, :subject end 11 From José Valim
  60. Add Associations to a Migration $ rails g resource article

    user:references subject body:text class CreateArticles < ActiveRecord::Migration def change create_table :articles do |t| t.references :user t.string :subject t.text :body t.timestamps end add_index :articles, :user_id end end class Article < ActiveRecord::Base belongs_to :user attr_accessible :body, :subject end $ rails g resource comment user:belongs_to article:belongs_to body:text 11 From José Valim
  61. Add Associations to a Migration $ rails g resource article

    user:references subject body:text class CreateArticles < ActiveRecord::Migration def change create_table :articles do |t| t.references :user t.string :subject t.text :body t.timestamps end add_index :articles, :user_id end end class Article < ActiveRecord::Base belongs_to :user attr_accessible :body, :subject end $ rails g resource comment user:belongs_to article:belongs_to body:text 11 From José Valim
  62. Show You the Status of the Database $ rake db:migrate:status

    database: db/development.sqlite3 Status Migration ID Migration Name -------------------------------------------------- up 20120414155612 Create users up 20120414160528 Create articles down 20120414161355 Create comments 12
  63. Show You the Status of the Database $ rake db:migrate:status

    database: db/development.sqlite3 Status Migration ID Migration Name -------------------------------------------------- up 20120414155612 Create users up 20120414160528 Create articles down 20120414161355 Create comments 12
  64. Import Your CSV Data 13 Name,Email James,james@example.com Dana,dana@example.com Summer,summer@example.com require

    "csv" namespace :users do desc "Import users from a CSV file" task :import => :environment do path = ENV.fetch("CSV_FILE") { File.join(File.dirname(__FILE__), *%w[.. .. db data users.csv]) } CSV.foreach(path, headers: true, header_converters: :symbol) do |row| User.create(row.to_hash) end end end
  65. Import Your CSV Data 13 Name,Email James,james@example.com Dana,dana@example.com Summer,summer@example.com require

    "csv" namespace :users do desc "Import users from a CSV file" task :import => :environment do path = ENV.fetch("CSV_FILE") { File.join(File.dirname(__FILE__), *%w[.. .. db data users.csv]) } CSV.foreach(path, headers: true, header_converters: :symbol) do |row| User.create(row.to_hash) end end end
  66. Import Your CSV Data 13 Name,Email James,james@example.com Dana,dana@example.com Summer,summer@example.com require

    "csv" namespace :users do desc "Import users from a CSV file" task :import => :environment do path = ENV.fetch("CSV_FILE") { File.join(File.dirname(__FILE__), *%w[.. .. db data users.csv]) } CSV.foreach(path, headers: true, header_converters: :symbol) do |row| User.create(row.to_hash) end end end
  67. Store CSV in Your Database 14 class Article < ActiveRecord::Base

    require "csv" module CSVSerializer module_function def load(field) field.to_s.parse_csv end def dump(object) Array(object).to_csv end end serialize :categories, CSVSerializer # ... attr_accessible :body, :subject, :categories end
  68. Store CSV in Your Database 14 class Article < ActiveRecord::Base

    require "csv" module CSVSerializer module_function def load(field) field.to_s.parse_csv end def dump(object) Array(object).to_csv end end serialize :categories, CSVSerializer # ... attr_accessible :body, :subject, :categories end
  69. Store CSV in Your Database 14 class Article < ActiveRecord::Base

    require "csv" module CSVSerializer module_function def load(field) field.to_s.parse_csv end def dump(object) Array(object).to_csv end end serialize :categories, CSVSerializer # ... attr_accessible :body, :subject, :categories end $ rails c Loading development environment (Rails 3.2.3) >> Article.create!(subject: "JEG2's Rails Hacks", categories: ["Rails", "Gray, James", "hacks"]) => #<Article id: 1, …> >> Article.last.categories => ["Rails", "Gray, James", "hacks"] >> exit $ sqlite3 db/development.sqlite3 'SELECT categories FROM articles ORDER BY created_at DESC LIMIT 1' -- Loading resources from /Users/james/.sqliterc categories -------------------------- Rails,"Gray, James",hacks
  70. Store CSV in Your Database 14 class Article < ActiveRecord::Base

    require "csv" module CSVSerializer module_function def load(field) field.to_s.parse_csv end def dump(object) Array(object).to_csv end end serialize :categories, CSVSerializer # ... attr_accessible :body, :subject, :categories end $ rails c Loading development environment (Rails 3.2.3) >> Article.create!(subject: "JEG2's Rails Hacks", categories: ["Rails", "Gray, James", "hacks"]) => #<Article id: 1, …> >> Article.last.categories => ["Rails", "Gray, James", "hacks"] >> exit $ sqlite3 db/development.sqlite3 'SELECT categories FROM articles ORDER BY created_at DESC LIMIT 1' -- Loading resources from /Users/james/.sqliterc categories -------------------------- Rails,"Gray, James",hacks
  71. Store CSV in Your Database 14 class Article < ActiveRecord::Base

    require "csv" module CSVSerializer module_function def load(field) field.to_s.parse_csv end def dump(object) Array(object).to_csv end end serialize :categories, CSVSerializer # ... attr_accessible :body, :subject, :categories end $ rails c Loading development environment (Rails 3.2.3) >> Article.create!(subject: "JEG2's Rails Hacks", categories: ["Rails", "Gray, James", "hacks"]) => #<Article id: 1, …> >> Article.last.categories => ["Rails", "Gray, James", "hacks"] >> exit $ sqlite3 db/development.sqlite3 'SELECT categories FROM articles ORDER BY created_at DESC LIMIT 1' -- Loading resources from /Users/james/.sqliterc categories -------------------------- Rails,"Gray, James",hacks
  72. “Pluck” Fields Out of Your Database 15 From Ryan Bates

    $ rails c Loading development environment (Rails 3.2.3) >> User.select(:email).map(&:email) User Load (0.1ms) SELECT email FROM "users" => ["james@example.com", "dana@example.com", "summer@example.com"] >> User.pluck(:email) (0.2ms) SELECT email FROM "users" => ["james@example.com", "dana@example.com", "summer@example.com"] >> User.uniq.pluck(:email) (0.2ms) SELECT DISTINCT email FROM "users" => ["dana@example.com", "james@example.com", "summer@example.com"]
  73. “Pluck” Fields Out of Your Database 15 From Ryan Bates

    $ rails c Loading development environment (Rails 3.2.3) >> User.select(:email).map(&:email) User Load (0.1ms) SELECT email FROM "users" => ["james@example.com", "dana@example.com", "summer@example.com"] >> User.pluck(:email) (0.2ms) SELECT email FROM "users" => ["james@example.com", "dana@example.com", "summer@example.com"] >> User.uniq.pluck(:email) (0.2ms) SELECT DISTINCT email FROM "users" => ["dana@example.com", "james@example.com", "summer@example.com"]
  74. “Pluck” Fields Out of Your Database 15 From Ryan Bates

    $ rails c Loading development environment (Rails 3.2.3) >> User.select(:email).map(&:email) User Load (0.1ms) SELECT email FROM "users" => ["james@example.com", "dana@example.com", "summer@example.com"] >> User.pluck(:email) (0.2ms) SELECT email FROM "users" => ["james@example.com", "dana@example.com", "summer@example.com"] >> User.uniq.pluck(:email) (0.2ms) SELECT DISTINCT email FROM "users" => ["dana@example.com", "james@example.com", "summer@example.com"]
  75. Count Records in Groups 16 $ rails g resource event

    article:belongs_to trigger
  76. Count Records in Groups 16 $ rails g resource event

    article:belongs_to trigger $ rails c Loading development environment (Rails 3.2.3) >> article = Article.last => #<Article id: 1, …> >> {edit: 3, view: 10}.each do |trigger, count| ?> count.times do ?> Event.new(trigger: trigger).tap { |e| e.article = article; e.save! } >> end >> end => {:edit=>3, :view=>10} >> Event.count => 13 >> Event.group(:trigger).count => {"edit"=>3, "view"=>10}
  77. Count Records in Groups 16 $ rails g resource event

    article:belongs_to trigger $ rails c Loading development environment (Rails 3.2.3) >> article = Article.last => #<Article id: 1, …> >> {edit: 3, view: 10}.each do |trigger, count| ?> count.times do ?> Event.new(trigger: trigger).tap { |e| e.article = article; e.save! } >> end >> end => {:edit=>3, :view=>10} >> Event.count => 13 >> Event.group(:trigger).count => {"edit"=>3, "view"=>10}
  78. Count Records in Groups 16 $ rails g resource event

    article:belongs_to trigger $ rails c Loading development environment (Rails 3.2.3) >> article = Article.last => #<Article id: 1, …> >> {edit: 3, view: 10}.each do |trigger, count| ?> count.times do ?> Event.new(trigger: trigger).tap { |e| e.article = article; e.save! } >> end >> end => {:edit=>3, :view=>10} >> Event.count => 13 >> Event.group(:trigger).count => {"edit"=>3, "view"=>10}
  79. Allow You to Override Associations 17 From Josh Susser class

    Car < ActiveRecord::Base belongs_to :owner belongs_to :previous_owner, class_name: "Owner" def owner=(new_owner) self.previous_owner = owner super end end
  80. Allow You to Override Associations 17 From Josh Susser class

    Car < ActiveRecord::Base belongs_to :owner belongs_to :previous_owner, class_name: "Owner" def owner=(new_owner) self.previous_owner = owner super end end
  81. Instantiate Records Without a Database 18 $ rails c Loading

    development environment (Rails 3.2.3) >> User.find(1) => #<User id: 1, name: "James", email: "james@example.com", …> >> jeg2 = User.instantiate("id" => 1, "email" => "james@example.com") => #<User id: 1, email: "james@example.com"> >> jeg2.name = "James Edward Gray II" => "James Edward Gray II" >> jeg2.save! => true >> User.find(1) => #<User id: 1, name: "James Edward Gray II", email: "james@example.com", …>
  82. Instantiate Records Without a Database 18 $ rails c Loading

    development environment (Rails 3.2.3) >> User.find(1) => #<User id: 1, name: "James", email: "james@example.com", …> >> jeg2 = User.instantiate("id" => 1, "email" => "james@example.com") => #<User id: 1, email: "james@example.com"> >> jeg2.name = "James Edward Gray II" => "James Edward Gray II" >> jeg2.save! => true >> User.find(1) => #<User id: 1, name: "James Edward Gray II", email: "james@example.com", …>
  83. Instantiate Records Without a Database 18 $ rails c Loading

    development environment (Rails 3.2.3) >> User.find(1) => #<User id: 1, name: "James", email: "james@example.com", …> >> jeg2 = User.instantiate("id" => 1, "email" => "james@example.com") => #<User id: 1, email: "james@example.com"> >> jeg2.name = "James Edward Gray II" => "James Edward Gray II" >> jeg2.save! => true >> User.find(1) => #<User id: 1, name: "James Edward Gray II", email: "james@example.com", …>
  84. Use Limitless Strings in PostgreSQL 19 From Josh Susser $

    rails g resource user bio # ... module PsqlApp class Application < Rails::Application # ... # Switch to limitless strings initializer "postgresql.no_default_string_limit" do ActiveSupport.on_load(:active_record) do adapter = ActiveRecord::ConnectionAdapters::PostgreSQLAdapter adapter::NATIVE_DATABASE_TYPES[:string].delete(:limit) end end end end
  85. Use Limitless Strings in PostgreSQL 19 From Josh Susser $

    rails g resource user bio $ rails c Loading development environment (Rails 3.2.3) >> very_long_bio = "X" * 10_000; :set => :set >> User.create!(bio: very_long_bio) => #<User id: 1, bio: "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX XX...", created_at: "2012-04-14 23:02:08", updated_at: "2012-04-14 23:02:08"> >> User.last.bio.size => 10000
  86. Use Limitless Strings in PostgreSQL 19 From Josh Susser $

    rails g resource user bio $ rails c Loading development environment (Rails 3.2.3) >> very_long_bio = "X" * 10_000; :set => :set >> User.create!(bio: very_long_bio) => #<User id: 1, bio: "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX XX...", created_at: "2012-04-14 23:02:08", updated_at: "2012-04-14 23:02:08"> >> User.last.bio.size => 10000
  87. Use Full Text Search in PostgreSQL 20 $ rails g

    resource article subject body:text From PeepCode
  88. Use Full Text Search in PostgreSQL 20 class CreateArticles <

    ActiveRecord::Migration def change create_table :articles do |t| t.string :subject t.text :body t.column :search, "tsvector" t.timestamps end execute <<-END_SQL CREATE INDEX articles_search_index ON articles USING gin(search); CREATE TRIGGER articles_search_update BEFORE INSERT OR UPDATE ON articles FOR EACH ROW EXECUTE PROCEDURE tsvector_update_trigger( search, 'pg_catalog.english', subject, body ); END_SQL end end From PeepCode
  89. Use Full Text Search in PostgreSQL 20 class CreateArticles <

    ActiveRecord::Migration def change create_table :articles do |t| t.string :subject t.text :body t.column :search, "tsvector" t.timestamps end execute <<-END_SQL CREATE INDEX articles_search_index ON articles USING gin(search); CREATE TRIGGER articles_search_update BEFORE INSERT OR UPDATE ON articles FOR EACH ROW EXECUTE PROCEDURE tsvector_update_trigger( search, 'pg_catalog.english', subject, body ); END_SQL end end From PeepCode
  90. Use Full Text Search in PostgreSQL 20 class CreateArticles <

    ActiveRecord::Migration def change create_table :articles do |t| t.string :subject t.text :body t.column :search, "tsvector" t.timestamps end execute <<-END_SQL CREATE INDEX articles_search_index ON articles USING gin(search); CREATE TRIGGER articles_search_update BEFORE INSERT OR UPDATE ON articles FOR EACH ROW EXECUTE PROCEDURE tsvector_update_trigger( search, 'pg_catalog.english', subject, body ); END_SQL end end From PeepCode
  91. Use Full Text Search in PostgreSQL 20 class CreateArticles <

    ActiveRecord::Migration def change create_table :articles do |t| t.string :subject t.text :body t.column :search, "tsvector" t.timestamps end execute <<-END_SQL CREATE INDEX articles_search_index ON articles USING gin(search); CREATE TRIGGER articles_search_update BEFORE INSERT OR UPDATE ON articles FOR EACH ROW EXECUTE PROCEDURE tsvector_update_trigger( search, 'pg_catalog.english', subject, body ); END_SQL end end From PeepCode
  92. Use Full Text Search in PostgreSQL 20 From PeepCode class

    Article < ActiveRecord::Base attr_accessible :body, :subject def self.search(query) sql = sanitize_sql_array(["plainto_tsquery('english', ?)", query]) where( "search @@ #{sql}" ).order( "ts_rank_cd(search, #{sql}) DESC" ) end end
  93. Use Full Text Search in PostgreSQL 20 From PeepCode class

    Article < ActiveRecord::Base attr_accessible :body, :subject def self.search(query) sql = sanitize_sql_array(["plainto_tsquery('english', ?)", query]) where( "search @@ #{sql}" ).order( "ts_rank_cd(search, #{sql}) DESC" ) end end
  94. Use Full Text Search in PostgreSQL 20 From PeepCode $

    rails c Loading development environment (Rails 3.2.3) >> Article.create!(subject: "Full Text Search") => #<Article id: 1, …> >> Article.create!(body: "A stemmed search.") => #<Article id: 2, …> >> Article.create!(body: "You won't find me!") => #<Article id: 3, …> >> Article.search("search").map { |a| a.subject || a.body } => ["Full Text Search", "A stemmed search."] >> Article.search("stemming").map { |a| a.subject || a.body } => ["A stemmed search."]
  95. Use Full Text Search in PostgreSQL 20 From PeepCode $

    rails c Loading development environment (Rails 3.2.3) >> Article.create!(subject: "Full Text Search") => #<Article id: 1, …> >> Article.create!(body: "A stemmed search.") => #<Article id: 2, …> >> Article.create!(body: "You won't find me!") => #<Article id: 3, …> >> Article.search("search").map { |a| a.subject || a.body } => ["Full Text Search", "A stemmed search."] >> Article.search("stemming").map { |a| a.subject || a.body } => ["A stemmed search."]
  96. Use Full Text Search in PostgreSQL 20 From PeepCode $

    rails c Loading development environment (Rails 3.2.3) >> Article.create!(subject: "Full Text Search") => #<Article id: 1, …> >> Article.create!(body: "A stemmed search.") => #<Article id: 2, …> >> Article.create!(body: "You won't find me!") => #<Article id: 3, …> >> Article.search("search").map { |a| a.subject || a.body } => ["Full Text Search", "A stemmed search."] >> Article.search("stemming").map { |a| a.subject || a.body } => ["A stemmed search."]
  97. Use Different a Database for Each User 21 def connect_to_user_database(name)

    config = ActiveRecord::Base.configurations["development"] .merge("database" => "db/#{name}.sqlite3") ActiveRecord::Base.establish_connection(config) end
  98. Use Different a Database for Each User 21 def connect_to_user_database(name)

    config = ActiveRecord::Base.configurations["development"] .merge("database" => "db/#{name}.sqlite3") ActiveRecord::Base.establish_connection(config) end
  99. Use Different a Database for Each User 21 def connect_to_user_database(name)

    config = ActiveRecord::Base.configurations["development"] .merge("database" => "db/#{name}.sqlite3") ActiveRecord::Base.establish_connection(config) end
  100. Use Different a Database for Each User 21 def connect_to_user_database(name)

    config = ActiveRecord::Base.configurations["development"] .merge("database" => "db/#{name}.sqlite3") ActiveRecord::Base.establish_connection(config) end require "user_database"
  101. Use Different a Database for Each User 21 namespace :db

    do desc "Add a new user database" task :add => %w[environment load_config] do name = ENV.fetch("DB_NAME") { fail "DB_NAME is required" } connect_to_user_database(name) ActiveRecord::Base.connection end namespace :migrate do desc "Migrate all user databases" task :all => %w[environment load_config] do ActiveRecord::Migration.verbose = ENV.fetch("VERBOSE", "true") == "true" Dir.glob("db/*.sqlite3") do |file| next if file == "db/test.sqlite3" connect_to_user_database(File.basename(file, ".sqlite3")) ActiveRecord::Migrator.migrate( ActiveRecord::Migrator.migrations_paths, ENV["VERSION"] && ENV["VERSION"].to_i ) do |migration| ENV["SCOPE"].blank? || (ENV["SCOPE"] == migration.scope) end end end end end
  102. Use Different a Database for Each User 21 namespace :db

    do desc "Add a new user database" task :add => %w[environment load_config] do name = ENV.fetch("DB_NAME") { fail "DB_NAME is required" } connect_to_user_database(name) ActiveRecord::Base.connection end namespace :migrate do desc "Migrate all user databases" task :all => %w[environment load_config] do ActiveRecord::Migration.verbose = ENV.fetch("VERBOSE", "true") == "true" Dir.glob("db/*.sqlite3") do |file| next if file == "db/test.sqlite3" connect_to_user_database(File.basename(file, ".sqlite3")) ActiveRecord::Migrator.migrate( ActiveRecord::Migrator.migrations_paths, ENV["VERSION"] && ENV["VERSION"].to_i ) do |migration| ENV["SCOPE"].blank? || (ENV["SCOPE"] == migration.scope) end end end end end
  103. Use Different a Database for Each User 21 $ rails

    g resource user name $ rake db:add DB_NAME=ruby_rogues $ rake db:add DB_NAME=grays $ rake db:migrate:all == CreateUsers: migrating ================================== -- create_table(:users) -> 0.0008s == CreateUsers: migrated (0.0008s) ========================= == CreateUsers: migrating ================================== -- create_table(:users) -> 0.0007s == CreateUsers: migrated (0.0008s) =========================
  104. Use Different a Database for Each User 21 $ rails

    g resource user name $ rake db:add DB_NAME=ruby_rogues $ rake db:add DB_NAME=grays $ rake db:migrate:all == CreateUsers: migrating ================================== -- create_table(:users) -> 0.0008s == CreateUsers: migrated (0.0008s) ========================= == CreateUsers: migrating ================================== -- create_table(:users) -> 0.0007s == CreateUsers: migrated (0.0008s) =========================
  105. Use Different a Database for Each User 21 $ rails

    g resource user name $ rake db:add DB_NAME=ruby_rogues $ rake db:add DB_NAME=grays $ rake db:migrate:all == CreateUsers: migrating ================================== -- create_table(:users) -> 0.0008s == CreateUsers: migrated (0.0008s) ========================= == CreateUsers: migrating ================================== -- create_table(:users) -> 0.0007s == CreateUsers: migrated (0.0008s) =========================
  106. Use Different a Database for Each User 21 $ rails

    c >> connect_to_user_database("ruby_rogues") => #<ActiveRecord::ConnectionAdapters::ConnectionPool…> >> User.create!(name: "Chuck") => #<User id: 1, name: "Chuck", …> >> User.create!(name: "Josh") => #<User id: 2, name: "Josh", …> >> User.create!(name: "Avdi") => #<User id: 3, name: "Avdi", …> … >> connect_to_user_database("grays") => #<ActiveRecord::ConnectionAdapters::ConnectionPool…> >> User.create!(name: "James") => #<User id: 1, name: "James", …> >> User.create!(name: "Dana") => #<User id: 2, name: "Dana", …> >> User.create!(name: "Summer") => #<User id: 3, name: "Summer", …>
  107. Use Different a Database for Each User 21 $ rails

    c >> connect_to_user_database("ruby_rogues") => #<ActiveRecord::ConnectionAdapters::ConnectionPool…> >> User.create!(name: "Chuck") => #<User id: 1, name: "Chuck", …> >> User.create!(name: "Josh") => #<User id: 2, name: "Josh", …> >> User.create!(name: "Avdi") => #<User id: 3, name: "Avdi", …> … >> connect_to_user_database("grays") => #<ActiveRecord::ConnectionAdapters::ConnectionPool…> >> User.create!(name: "James") => #<User id: 1, name: "James", …> >> User.create!(name: "Dana") => #<User id: 2, name: "Dana", …> >> User.create!(name: "Summer") => #<User id: 3, name: "Summer", …>
  108. Use Different a Database for Each User 21 $ rails

    c >> connect_to_user_database("ruby_rogues") => #<ActiveRecord::ConnectionAdapters::ConnectionPool…> >> User.create!(name: "Chuck") => #<User id: 1, name: "Chuck", …> >> User.create!(name: "Josh") => #<User id: 2, name: "Josh", …> >> User.create!(name: "Avdi") => #<User id: 3, name: "Avdi", …> … >> connect_to_user_database("grays") => #<ActiveRecord::ConnectionAdapters::ConnectionPool…> >> User.create!(name: "James") => #<User id: 1, name: "James", …> >> User.create!(name: "Dana") => #<User id: 2, name: "Dana", …> >> User.create!(name: "Summer") => #<User id: 3, name: "Summer", …>
  109. Use Different a Database for Each User 21 class ApplicationController

    < ActionController::Base protect_from_forgery before_filter :connect_to_database private def connect_to_database connect_to_user_database(request.subdomains.first) end end
  110. Use Different a Database for Each User 21 class ApplicationController

    < ActionController::Base protect_from_forgery before_filter :connect_to_database private def connect_to_database connect_to_user_database(request.subdomains.first) end end
  111. Use Different a Database for Each User 21

  112. Use Different a Database for Each User 21

  113. Intermission Am I going to make it???

  114. Why Do This? I’m trying to give you new ideas

    Studies show this will help you solve Rails problems Also, it’s fun! Remember to have fun
  115. Less Talk, More Tricks!!!

  116. Refine Your Fashion Sense http://www.flickr.com/photos/oreillyconf/5735037920/ 22

  117. Refine Your Fashion Sense http://www.flickr.com/photos/oreillyconf/5735037920/ http://www.flickr.com/photos/oreillyconf/5735038376/ 22

  118. Refine Your Fashion Sense http://www.flickr.com/photos/oreillyconf/5735037920/ http://www.flickr.com/photos/oreillyconf/5735038376/ http://www.flickr.com/photos/aaronp/4609780419/ 22

  119. Ruby Extensions Updating Ruby’s fashion sense

  120. Write Files Atomically 23 class Comment < ActiveRecord::Base # ...

    Q_DIR = (Rails.root + "comment_queue").tap(&:mkpath) after_save :queue_comment def queue_comment File.atomic_write(Q_DIR + "#{id}.txt") do |f| f.puts "Article: #{article.subject}" f.puts "User: #{user.name}" f.puts body end end end
  121. Write Files Atomically 23 class Comment < ActiveRecord::Base # ...

    Q_DIR = (Rails.root + "comment_queue").tap(&:mkpath) after_save :queue_comment def queue_comment File.atomic_write(Q_DIR + "#{id}.txt") do |f| f.puts "Article: #{article.subject}" f.puts "User: #{user.name}" f.puts body end end end
  122. Write Files Atomically 23 $ ls comment_queue ls: comment_queue: No

    such file or directory $ rails r 'Comment.new(body: "Queue me.").tap { |c| c.article, c.user = Article.first, User.first; c.save! }' $ ls comment_queue 1.txt $ cat comment_queue/1.txt Article: JEG2's Rails Hacks User: James Edward Gray II Queue me.
  123. Write Files Atomically 23 $ ls comment_queue ls: comment_queue: No

    such file or directory $ rails r 'Comment.new(body: "Queue me.").tap { |c| c.article, c.user = Article.first, User.first; c.save! }' $ ls comment_queue 1.txt $ cat comment_queue/1.txt Article: JEG2's Rails Hacks User: James Edward Gray II Queue me.
  124. Merge Nested Hashes 24 $ rails c Loading development environment

    (Rails 3.2.3) >> {nested: {one: 1}}.merge(nested: {two: 2}) => {:nested=>{:two=>2}} >> {nested: {one: 1}}.deep_merge(nested: {two: 2}) => {:nested=>{:one=>1, :two=>2}}
  125. Merge Nested Hashes 24 $ rails c Loading development environment

    (Rails 3.2.3) >> {nested: {one: 1}}.merge(nested: {two: 2}) => {:nested=>{:two=>2}} >> {nested: {one: 1}}.deep_merge(nested: {two: 2}) => {:nested=>{:one=>1, :two=>2}}
  126. Remove Specific Keys From a Hash 25 $ rails c

    Loading development environment (Rails 3.2.3) >> params = {controller: "home", action: "index", from: "Google"} => {:controller=>"home", :action=>"index", :from=>"Google"} >> params.except(:controller, :action) => {:from=>"Google"}
  127. Remove Specific Keys From a Hash 25 $ rails c

    Loading development environment (Rails 3.2.3) >> params = {controller: "home", action: "index", from: "Google"} => {:controller=>"home", :action=>"index", :from=>"Google"} >> params.except(:controller, :action) => {:from=>"Google"}
  128. Add Defaults to Hash 26 $ rails c Loading development

    environment (Rails 3.2.3) >> {required: true}.merge(optional: true) => {:required=>true, :optional=>true} >> {required: true}.reverse_merge(optional: true) => {:optional=>true, :required=>true} >> {required: true, optional: false}.merge(optional: true) => {:required=>true, :optional=>true} >> {required: true, optional: false}.reverse_merge(optional: true) => {:optional=>false, :required=>true}
  129. Add Defaults to Hash 26 $ rails c Loading development

    environment (Rails 3.2.3) >> {required: true}.merge(optional: true) => {:required=>true, :optional=>true} >> {required: true}.reverse_merge(optional: true) => {:optional=>true, :required=>true} >> {required: true, optional: false}.merge(optional: true) => {:required=>true, :optional=>true} >> {required: true, optional: false}.reverse_merge(optional: true) => {:optional=>false, :required=>true}
  130. Add Defaults to Hash 26 $ rails c Loading development

    environment (Rails 3.2.3) >> {required: true}.merge(optional: true) => {:required=>true, :optional=>true} >> {required: true}.reverse_merge(optional: true) => {:optional=>true, :required=>true} >> {required: true, optional: false}.merge(optional: true) => {:required=>true, :optional=>true} >> {required: true, optional: false}.reverse_merge(optional: true) => {:optional=>false, :required=>true}
  131. Add Defaults to Hash 26 $ rails c Loading development

    environment (Rails 3.2.3) >> {required: true}.merge(optional: true) => {:required=>true, :optional=>true} >> {required: true}.reverse_merge(optional: true) => {:optional=>true, :required=>true} >> {required: true, optional: false}.merge(optional: true) => {:required=>true, :optional=>true} >> {required: true, optional: false}.reverse_merge(optional: true) => {:optional=>false, :required=>true}
  132. Answer Questions About Strings 27 $ rails g migration add_status_to_articles

    status
  133. Answer Questions About Strings 27 $ rails g migration add_status_to_articles

    status class AddStatusToArticles < ActiveRecord::Migration def change add_column :articles, :status, :string, default: "Draft", null: false end end
  134. Answer Questions About Strings 27 $ rails g migration add_status_to_articles

    status class AddStatusToArticles < ActiveRecord::Migration def change add_column :articles, :status, :string, default: "Draft", null: false end end
  135. Answer Questions About Strings 27 $ rails c Loading development

    environment (Rails 3.2.3) >> env = Rails.env => "development" >> env.development? => true >> env.test? => false >> "magic".inquiry.magic? => true >> article = Article.first => #<Article id: 1, …, status: "Draft"> >> article.draft? => true >> article.published? => false
  136. Answer Questions About Strings 27 $ rails c Loading development

    environment (Rails 3.2.3) >> env = Rails.env => "development" >> env.development? => true >> env.test? => false >> "magic".inquiry.magic? => true >> article = Article.first => #<Article id: 1, …, status: "Draft"> >> article.draft? => true >> article.published? => false
  137. Answer Questions About Strings 27 $ rails c Loading development

    environment (Rails 3.2.3) >> env = Rails.env => "development" >> env.development? => true >> env.test? => false >> "magic".inquiry.magic? => true >> article = Article.first => #<Article id: 1, …, status: "Draft"> >> article.draft? => true >> article.published? => false
  138. Answer Questions About Strings 27 $ rails c Loading development

    environment (Rails 3.2.3) >> env = Rails.env => "development" >> env.development? => true >> env.test? => false >> "magic".inquiry.magic? => true >> article = Article.first => #<Article id: 1, …, status: "Draft"> >> article.draft? => true >> article.published? => false
  139. Answer Questions About Strings 27 class Article < ActiveRecord::Base #

    ... STATUSES = %w[Draft Published] validates_inclusion_of :status, in: STATUSES def method_missing(method, *args, &block) if method =~ /\A#{STATUSES.map(&:downcase).join("|")}\?\z/ status.downcase.inquiry.send(method) else super end end end
  140. Answer Questions About Strings 27 class Article < ActiveRecord::Base #

    ... STATUSES = %w[Draft Published] validates_inclusion_of :status, in: STATUSES def method_missing(method, *args, &block) if method =~ /\A#{STATUSES.map(&:downcase).join("|")}\?\z/ status.downcase.inquiry.send(method) else super end end end
  141. Answer Questions About Strings 27 class Article < ActiveRecord::Base #

    ... STATUSES = %w[Draft Published] validates_inclusion_of :status, in: STATUSES def method_missing(method, *args, &block) if method =~ /\A#{STATUSES.map(&:downcase).join("|")}\?\z/ status.downcase.inquiry.send(method) else super end end end
  142. Get you on the cover of a magazine The hairdo

    may be required http://www.rubyinside.com/rubys-popularity-scales-new-heights-19.html 28
  143. Get you voted “Hottest Hacker” http://pageman.multiply.com/links/item/21/David_Heinemeier_Hanssons_Blog 29

  144. Get you voted “Hottest Hacker” http://pageman.multiply.com/links/item/21/David_Heinemeier_Hanssons_Blog 29

  145. Get you voted “Hottest Hacker” http://pageman.multiply.com/links/item/21/David_Heinemeier_Hanssons_Blog http://torrentfreak.com/richard-stallman-opts-to-disobey-anti-piracy-law-110610/ 29

  146. Views It’s all about how we look

  147. Hide Comments From Your Users 30 <!-- HTML comments stay

    in the rendered content --> <%# ERb comments do not %> <h1>Home Page</h1> From The Rails View
  148. Hide Comments From Your Users 30 <!-- HTML comments stay

    in the rendered content --> <%# ERb comments do not %> <h1>Home Page</h1> From The Rails View
  149. Hide Comments From Your Users 30 <!-- HTML comments stay

    in the rendered content --> <%# ERb comments do not %> <h1>Home Page</h1> <body> <!-- HTML comments stay in the rendered content --> <h1>Home Page</h1> </body> From The Rails View
  150. Understand a Shorter ERb Syntax 31 # ... module Blog

    class Application < Rails::Application # ... # Broken: config.action_view.erb_trim_mode = '%' ActionView::Template::Handlers::ERB.erb_implementation = Class.new(ActionView::Template::Handlers::Erubis) do include ::Erubis::PercentLineEnhancer end end end % if current_user.try(:admin?) <%= render "edit_links" %> % end
  151. Understand a Shorter ERb Syntax 31 # ... module Blog

    class Application < Rails::Application # ... # Broken: config.action_view.erb_trim_mode = '%' ActionView::Template::Handlers::ERB.erb_implementation = Class.new(ActionView::Template::Handlers::Erubis) do include ::Erubis::PercentLineEnhancer end end end % if current_user.try(:admin?) <%= render "edit_links" %> % end
  152. Understand a Shorter ERb Syntax 31 # ... module Blog

    class Application < Rails::Application # ... # Broken: config.action_view.erb_trim_mode = '%' ActionView::Template::Handlers::ERB.erb_implementation = Class.new(ActionView::Template::Handlers::Erubis) do include ::Erubis::PercentLineEnhancer end end end % if current_user.try(:admin?) <%= render "edit_links" %> % end
  153. Understand a Shorter ERb Syntax 31 # ... module Blog

    class Application < Rails::Application # ... # Broken: config.action_view.erb_trim_mode = '%' ActionView::Template::Handlers::ERB.erb_implementation = Class.new(ActionView::Template::Handlers::Erubis) do include ::Erubis::PercentLineEnhancer end end end % if current_user.try(:admin?) <%= render "edit_links" %> % end
  154. Use Blocks to Avoid Assignments in Views 32 <table> <%

    @cart.products.each do |product| %> <tr> <td><%= product.name %></td> <td><%= number_to_currency product.price %></td> </tr> <% end %> <tr> <td>Subtotal</td> <td><%= number_to_currency @cart.total %></td> </tr> <tr> <td>Tax</td> <td><%= number_to_currency(tax = calculate_tax(@cart.total)) %></td> </tr> <tr> <td>Total</td> <td><%= number_to_currency(@cart.total + tax) %></td> </tr> </table> From The Rails View
  155. Use Blocks to Avoid Assignments in Views 32 <table> <%

    @cart.products.each do |product| %> <tr> <td><%= product.name %></td> <td><%= number_to_currency product.price %></td> </tr> <% end %> <tr> <td>Subtotal</td> <td><%= number_to_currency @cart.total %></td> </tr> <tr> <td>Tax</td> <td><%= number_to_currency(tax = calculate_tax(@cart.total)) %></td> </tr> <tr> <td>Total</td> <td><%= number_to_currency(@cart.total + tax) %></td> </tr> </table> From The Rails View
  156. Use Blocks to Avoid Assignments in Views 32 <table> <%

    @cart.products.each do |product| %> <tr> <td><%= product.name %></td> <td><%= number_to_currency product.price %></td> </tr> <% end %> <tr> <td>Subtotal</td> <td><%= number_to_currency @cart.total %></td> </tr> <tr> <td>Tax</td> <td><%= number_to_currency(tax = calculate_tax(@cart.total)) %></td> </tr> <tr> <td>Total</td> <td><%= number_to_currency(@cart.total + tax) %></td> </tr> </table> From The Rails View
  157. <table> <% @cart.products.each do |product| %> <tr> <td><%= product.name %></td>

    <td><%= number_to_currency product.price %></td> </tr> <% end %> <tr> <td>Subtotal</td> <td><%= number_to_currency @cart.total %></td> </tr> <% calculate_tax @cart.total do |tax| %> <tr> <td>Tax</td> <td><%= number_to_currency tax %></td> </tr> <tr> <td>Total</td> <td><%= number_to_currency(@cart.total + tax) %></td> </tr> <% end %> </table> Use Blocks to Avoid Assignments in Views 32 From The Rails View
  158. <table> <% @cart.products.each do |product| %> <tr> <td><%= product.name %></td>

    <td><%= number_to_currency product.price %></td> </tr> <% end %> <tr> <td>Subtotal</td> <td><%= number_to_currency @cart.total %></td> </tr> <% calculate_tax @cart.total do |tax| %> <tr> <td>Tax</td> <td><%= number_to_currency tax %></td> </tr> <tr> <td>Total</td> <td><%= number_to_currency(@cart.total + tax) %></td> </tr> <% end %> </table> Use Blocks to Avoid Assignments in Views 32 From The Rails View
  159. Use Blocks to Avoid Assignments in Views 32 module CartHelper

    def calculate_tax(total, user = current_user) tax = TaxTable.for(user).calculate(total) if block_given? yield tax else tax end end end From The Rails View
  160. Use Blocks to Avoid Assignments in Views 32 module CartHelper

    def calculate_tax(total, user = current_user) tax = TaxTable.for(user).calculate(total) if block_given? yield tax else tax end end end From The Rails View
  161. Generate Multiple Tags at Once 33 From José Valim <h1>Articles</h1>

    <% @articles.each do |article| %> <%= content_tag_for(:div, article) do %> <h2><%= article.subject %></h2> <% end %> <% end %>
  162. Generate Multiple Tags at Once 33 From José Valim <h1>Articles</h1>

    <% @articles.each do |article| %> <%= content_tag_for(:div, article) do %> <h2><%= article.subject %></h2> <% end %> <% end %>
  163. Generate Multiple Tags at Once 33 From José Valim <h1>Articles</h1>

    <% @articles.each do |article| %> <%= content_tag_for(:div, article) do %> <h2><%= article.subject %></h2> <% end %> <% end %> <h1>Articles</h1> <%= content_tag_for(:div, @articles) do |article| %> <h2><%= article.subject %></h2> <% end %>
  164. Generate Multiple Tags at Once 33 From José Valim <h1>Articles</h1>

    <% @articles.each do |article| %> <%= content_tag_for(:div, article) do %> <h2><%= article.subject %></h2> <% end %> <% end %> <h1>Articles</h1> <%= content_tag_for(:div, @articles) do |article| %> <h2><%= article.subject %></h2> <% end %>
  165. Render Any Object 34 From José Valim class Event <

    ActiveRecord::Base # ... def to_partial_path "events/#{trigger}" # events/edit or events/view end end
  166. Render Any Object 34 From José Valim class Event <

    ActiveRecord::Base # ... def to_partial_path "events/#{trigger}" # events/edit or events/view end end <%= render partial: @events, as: :event %>
  167. Render Any Object 34 From José Valim class Event <

    ActiveRecord::Base # ... def to_partial_path "events/#{trigger}" # events/edit or events/view end end <%= render partial: @events, as: :event %>
  168. Render Any Object 34 From José Valim class Event <

    ActiveRecord::Base # ... def to_partial_path "events/#{trigger}" # events/edit or events/view end end <%= render partial: @events, as: :event %>
  169. Group Menu Entries 35 From The Rails View

  170. Group Menu Entries 35 From The Rails View <%= select_tag(

    :grouped_menu, grouped_options_for_select( "Group A" => %w[One Two Three], "Group B" => %w[One Two Three] ) ) %>
  171. Group Menu Entries 35 From The Rails View <%= select_tag(

    :grouped_menu, grouped_options_for_select( "Group A" => %w[One Two Three], "Group B" => %w[One Two Three] ) ) %>
  172. Build Forms the Way You Like Them 36 From The

    Rails View class LabeledFieldsWithErrors < ActionView::Helpers::FormBuilder def errors_for(attribute) if (errors = object.errors[attribute]).any? @template.content_tag(:span, errors.to_sentence, class: "error") end end def method_missing(method, *args, &block) if %r{ \A (?<labeled>labeled_)? (?<wrapped>\w+?) (?<with_errors>_with_errors)? \z }x =~ method and respond_to?(wrapped) and [labeled, with_errors].any?(&:present?) attribute, tags = args.first, [ ] tags << label(attribute) if labeled.present? tags << send(wrapped, *args, &block) tags << errors_for(attribute) if with_errors.present? tags.join(" ").html_safe else super end end end
  173. Build Forms the Way You Like Them 36 From The

    Rails View class LabeledFieldsWithErrors < ActionView::Helpers::FormBuilder def errors_for(attribute) if (errors = object.errors[attribute]).any? @template.content_tag(:span, errors.to_sentence, class: "error") end end def method_missing(method, *args, &block) if %r{ \A (?<labeled>labeled_)? (?<wrapped>\w+?) (?<with_errors>_with_errors)? \z }x =~ method and respond_to?(wrapped) and [labeled, with_errors].any?(&:present?) attribute, tags = args.first, [ ] tags << label(attribute) if labeled.present? tags << send(wrapped, *args, &block) tags << errors_for(attribute) if with_errors.present? tags.join(" ").html_safe else super end end end
  174. Build Forms the Way You Like Them 36 From The

    Rails View class LabeledFieldsWithErrors < ActionView::Helpers::FormBuilder def errors_for(attribute) if (errors = object.errors[attribute]).any? @template.content_tag(:span, errors.to_sentence, class: "error") end end def method_missing(method, *args, &block) if %r{ \A (?<labeled>labeled_)? (?<wrapped>\w+?) (?<with_errors>_with_errors)? \z }x =~ method and respond_to?(wrapped) and [labeled, with_errors].any?(&:present?) attribute, tags = args.first, [ ] tags << label(attribute) if labeled.present? tags << send(wrapped, *args, &block) tags << errors_for(attribute) if with_errors.present? tags.join(" ").html_safe else super end end end
  175. Build Forms the Way You Like Them 36 From The

    Rails View class LabeledFieldsWithErrors < ActionView::Helpers::FormBuilder def errors_for(attribute) if (errors = object.errors[attribute]).any? @template.content_tag(:span, errors.to_sentence, class: "error") end end def method_missing(method, *args, &block) if %r{ \A (?<labeled>labeled_)? (?<wrapped>\w+?) (?<with_errors>_with_errors)? \z }x =~ method and respond_to?(wrapped) and [labeled, with_errors].any?(&:present?) attribute, tags = args.first, [ ] tags << label(attribute) if labeled.present? tags << send(wrapped, *args, &block) tags << errors_for(attribute) if with_errors.present? tags.join(" ").html_safe else super end end end
  176. Build Forms the Way You Like Them 36 From The

    Rails View # ... module Blog class Application < Rails::Application # ... require "labeled_fields_with_errors" config.action_view.default_form_builder = LabeledFieldsWithErrors config.action_view.field_error_proc = ->(field, _) { field } end end
  177. Build Forms the Way You Like Them 36 From The

    Rails View # ... module Blog class Application < Rails::Application # ... require "labeled_fields_with_errors" config.action_view.default_form_builder = LabeledFieldsWithErrors config.action_view.field_error_proc = ->(field, _) { field } end end
  178. Build Forms the Way You Like Them 36 From The

    Rails View # ... module Blog class Application < Rails::Application # ... require "labeled_fields_with_errors" config.action_view.default_form_builder = LabeledFieldsWithErrors config.action_view.field_error_proc = ->(field, _) { field } end end
  179. Build Forms the Way You Like Them 36 From The

    Rails View <%= form_for @article do |f| %> <p><%= f.text_field :subject %></p> <p><%= f.labeled_text_field :subject %></p> <p><%= f.text_field_with_errors :subject %></p> <p><%= f.labeled_text_field_with_errors :subject %></p> <%= f.submit %> <% end %>
  180. Build Forms the Way You Like Them 36 From The

    Rails View <%= form_for @article do |f| %> <p><%= f.text_field :subject %></p> <p><%= f.labeled_text_field :subject %></p> <p><%= f.text_field_with_errors :subject %></p> <p><%= f.labeled_text_field_with_errors :subject %></p> <%= f.submit %> <% end %>
  181. Build Forms the Way You Like Them 36 From The

    Rails View <!-- ... --> <p><input id="article_subject" name="article[subject]" size="30" type="text" value="" /></p> <p><label for="article_subject">Subject</label> <input id="article_subject" name="article[subject]" size="30" type="text" value="" /></p> <p><input id="article_subject" name="article[subject]" size="30" type="text" value="" /> <span class="error">can't be blank</span></p> <p><label for="article_subject">Subject</label> <input id="article_subject" name="article[subject]" size="30" type="text" value="" /> <span class="error">can't be blank</span></p> <!-- ... -->
  182. Build Forms the Way You Like Them 36 From The

    Rails View <!-- ... --> <p><input id="article_subject" name="article[subject]" size="30" type="text" value="" /></p> <p><label for="article_subject">Subject</label> <input id="article_subject" name="article[subject]" size="30" type="text" value="" /></p> <p><input id="article_subject" name="article[subject]" size="30" type="text" value="" /> <span class="error">can't be blank</span></p> <p><label for="article_subject">Subject</label> <input id="article_subject" name="article[subject]" size="30" type="text" value="" /> <span class="error">can't be blank</span></p> <!-- ... -->
  183. Build Forms the Way You Like Them 36 From The

    Rails View <!-- ... --> <p><input id="article_subject" name="article[subject]" size="30" type="text" value="" /></p> <p><label for="article_subject">Subject</label> <input id="article_subject" name="article[subject]" size="30" type="text" value="" /></p> <p><input id="article_subject" name="article[subject]" size="30" type="text" value="" /> <span class="error">can't be blank</span></p> <p><label for="article_subject">Subject</label> <input id="article_subject" name="article[subject]" size="30" type="text" value="" /> <span class="error">can't be blank</span></p> <!-- ... -->
  184. Inspire Theme Songs About Your Work http://www.confreaks.com/videos/529-farmhouseconf-ruby-hero-tenderlove 37

  185. The Router and Controllers They carry the theme of our

    applications
  186. Route Exceptions From José Valim 38 # ... module Blog

    class Application < Rails::Application # ... config.exceptions_app = routes end end
  187. Route Exceptions From José Valim 38 # ... module Blog

    class Application < Rails::Application # ... config.exceptions_app = routes end end
  188. Route Exceptions From José Valim 38 # ... module Blog

    class Application < Rails::Application # ... config.exceptions_app = routes end end Blog::Application.routes.draw do # ... match "/404", to: "errors#not_found" end
  189. Route Exceptions From José Valim 38 # ... module Blog

    class Application < Rails::Application # ... config.exceptions_app = routes end end Blog::Application.routes.draw do # ... match "/404", to: "errors#not_found" end
  190. Route to Sinatra From Crafting Rails Applications 39 source 'https://rubygems.org'

    # ... gem "resque", require: "resque/server"
  191. Route to Sinatra From Crafting Rails Applications 39 source 'https://rubygems.org'

    # ... gem "resque", require: "resque/server"
  192. Route to Sinatra From Crafting Rails Applications 39 source 'https://rubygems.org'

    # ... gem "resque", require: "resque/server" module AdminValidator module_function def matches?(request) if (id = request.env["rack.session"]["user_id"]) current_user = User.find_by_id(id) current_user.try(:admin?) else false end end end
  193. Route to Sinatra From Crafting Rails Applications 39 source 'https://rubygems.org'

    # ... gem "resque", require: "resque/server" module AdminValidator module_function def matches?(request) if (id = request.env["rack.session"]["user_id"]) current_user = User.find_by_id(id) current_user.try(:admin?) else false end end end
  194. Route to Sinatra From Crafting Rails Applications 39 source 'https://rubygems.org'

    # ... gem "resque", require: "resque/server" module AdminValidator module_function def matches?(request) if (id = request.env["rack.session"]["user_id"]) current_user = User.find_by_id(id) current_user.try(:admin?) else false end end end
  195. Route to Sinatra From Crafting Rails Applications 39 Blog::Application.routes.draw do

    # ... require "admin_validator" constraints AdminValidator do mount Resque::Server, at: "/admin/resque" end end
  196. Route to Sinatra From Crafting Rails Applications 39 Blog::Application.routes.draw do

    # ... require "admin_validator" constraints AdminValidator do mount Resque::Server, at: "/admin/resque" end end
  197. Route to Sinatra From Crafting Rails Applications 39 Blog::Application.routes.draw do

    # ... require "admin_validator" constraints AdminValidator do mount Resque::Server, at: "/admin/resque" end end
  198. Route to Sinatra From Crafting Rails Applications 39 Blog::Application.routes.draw do

    # ... require "admin_validator" constraints AdminValidator do mount Resque::Server, at: "/admin/resque" end end
  199. Stream CSV to Users 40 class ArticlesController < ApplicationController def

    index respond_to do |format| format.html do @articles = Article.all end format.csv do headers["Content-Disposition"] = %Q{attachment; filename="articles.csv"} self.response_body = Enumerator.new do |response| csv = CSV.new(response, row_sep: "\n") csv << %w[Subject Created Status] Article.find_each do |article| csv << [ article.subject, article.created_at.to_s(:long), article.status ] end end end end end # ... end
  200. Stream CSV to Users 40 class ArticlesController < ApplicationController def

    index respond_to do |format| format.html do @articles = Article.all end format.csv do headers["Content-Disposition"] = %Q{attachment; filename="articles.csv"} self.response_body = Enumerator.new do |response| csv = CSV.new(response, row_sep: "\n") csv << %w[Subject Created Status] Article.find_each do |article| csv << [ article.subject, article.created_at.to_s(:long), article.status ] end end end end end # ... end
  201. Stream CSV to Users 40 class ArticlesController < ApplicationController def

    index respond_to do |format| format.html do @articles = Article.all end format.csv do headers["Content-Disposition"] = %Q{attachment; filename="articles.csv"} self.response_body = Enumerator.new do |response| csv = CSV.new(response, row_sep: "\n") csv << %w[Subject Created Status] Article.find_each do |article| csv << [ article.subject, article.created_at.to_s(:long), article.status ] end end end end end # ... end
  202. Stream CSV to Users 40 class ArticlesController < ApplicationController def

    index respond_to do |format| format.html do @articles = Article.all end format.csv do headers["Content-Disposition"] = %Q{attachment; filename="articles.csv"} self.response_body = Enumerator.new do |response| csv = CSV.new(response, row_sep: "\n") csv << %w[Subject Created Status] Article.find_each do |article| csv << [ article.subject, article.created_at.to_s(:long), article.status ] end end end end end # ... end
  203. Stream CSV to Users 40 class ArticlesController < ApplicationController def

    index respond_to do |format| format.html do @articles = Article.all end format.csv do headers["Content-Disposition"] = %Q{attachment; filename="articles.csv"} self.response_body = Enumerator.new do |response| csv = CSV.new(response, row_sep: "\n") csv << %w[Subject Created Status] Article.find_each do |article| csv << [ article.subject, article.created_at.to_s(:long), article.status ] end end end end end # ... end
  204. Stream CSV to Users 40 class ArticlesController < ApplicationController def

    index respond_to do |format| format.html do @articles = Article.all end format.csv do headers["Content-Disposition"] = %Q{attachment; filename="articles.csv"} self.response_body = Enumerator.new do |response| csv = CSV.new(response, row_sep: "\n") csv << %w[Subject Created Status] Article.find_each do |article| csv << [ article.subject, article.created_at.to_s(:long), article.status ] end end end end end # ... end
  205. Do Some Work in the Background From Crafting Rails Applications

    41 $ rails g migration add_stats_to_articles stats:text
  206. Do Some Work in the Background From Crafting Rails Applications

    41 $ rails g migration add_stats_to_articles stats:text
  207. Do Some Work in the Background From Crafting Rails Applications

    41 class Article < ActiveRecord::Base # ... serialize :stats def calculate_stats words = Hash.new(0) body.to_s.scan(/\S+/) { |word| words[word] += 1 } sleep 10 # simulate a lot of work self.stats = {words: words} end end $ rails g migration add_stats_to_articles stats:text
  208. Do Some Work in the Background From Crafting Rails Applications

    41 class Article < ActiveRecord::Base # ... serialize :stats def calculate_stats words = Hash.new(0) body.to_s.scan(/\S+/) { |word| words[word] += 1 } sleep 10 # simulate a lot of work self.stats = {words: words} end end $ rails g migration add_stats_to_articles stats:text
  209. Do Some Work in the Background From Crafting Rails Applications

    41 class Article < ActiveRecord::Base # ... require "thread" def self.queue; @queue ||= Queue.new end def self.thread @thread ||= Thread.new do while job = queue.pop job.call end end end thread # start the Thread end
  210. Do Some Work in the Background From Crafting Rails Applications

    41 class Article < ActiveRecord::Base # ... require "thread" def self.queue; @queue ||= Queue.new end def self.thread @thread ||= Thread.new do while job = queue.pop job.call end end end thread # start the Thread end
  211. Do Some Work in the Background From Crafting Rails Applications

    41 class Article < ActiveRecord::Base # ... require "thread" def self.queue; @queue ||= Queue.new end def self.thread @thread ||= Thread.new do while job = queue.pop job.call end end end thread # start the Thread end
  212. Do Some Work in the Background From Crafting Rails Applications

    41 class Article < ActiveRecord::Base # ... require "thread" def self.queue; @queue ||= Queue.new end def self.thread @thread ||= Thread.new do while job = queue.pop job.call end end end thread # start the Thread end
  213. Do Some Work in the Background From Crafting Rails Applications

    41 class Article < ActiveRecord::Base # ... require "thread" def self.queue; @queue ||= Queue.new end def self.thread @thread ||= Thread.new do while job = queue.pop job.call end end end thread # start the Thread end
  214. Do Some Work in the Background From Crafting Rails Applications

    41 class Article < ActiveRecord::Base # ... after_create :add_stats def add_stats self.class.queue << -> { calculate_stats; save } end end
  215. Do Some Work in the Background From Crafting Rails Applications

    41 class Article < ActiveRecord::Base # ... after_create :add_stats def add_stats self.class.queue << -> { calculate_stats; save } end end
  216. Do Some Work in the Background From Crafting Rails Applications

    41 $ rails c Loading development environment (Rails 3.2.3) >> Article.create!(subject: "Stats", body: "Lorem ipsum…"); Time.now.strftime("%H:%M:%S") => "15:24:10" >> [Article.last.stats, Time.now.strftime("%H:%M:%S")] => [nil, "15:24:13"] >> [Article.last.stats, Time.now.strftime("%H:%M:%S")] =>[{:words=>{"Lorem"=>1, "ipsum"=>1, …}, "15:24:26"]
  217. Do Some Work in the Background From Crafting Rails Applications

    41 $ rails c Loading development environment (Rails 3.2.3) >> Article.create!(subject: "Stats", body: "Lorem ipsum…"); Time.now.strftime("%H:%M:%S") => "15:24:10" >> [Article.last.stats, Time.now.strftime("%H:%M:%S")] => [nil, "15:24:13"] >> [Article.last.stats, Time.now.strftime("%H:%M:%S")] =>[{:words=>{"Lorem"=>1, "ipsum"=>1, …}, "15:24:26"]
  218. Do Some Work in the Background From Crafting Rails Applications

    41 $ rails c Loading development environment (Rails 3.2.3) >> Article.create!(subject: "Stats", body: "Lorem ipsum…"); Time.now.strftime("%H:%M:%S") => "15:24:10" >> [Article.last.stats, Time.now.strftime("%H:%M:%S")] => [nil, "15:24:13"] >> [Article.last.stats, Time.now.strftime("%H:%M:%S")] =>[{:words=>{"Lorem"=>1, "ipsum"=>1, …}, "15:24:26"]
  219. Have We All Learned Something New Yet?!

  220. Publish a Static Site Using Rails 42 Static::Application.configure do #

    ... # Show full error reports and disable caching config.consider_all_requests_local = true config.action_controller.perform_caching = !!ENV["GENERATING_SITE"] # ... # Don't fallback to assets pipeline if a precompiled asset is missed config.assets.compile = !ENV["GENERATING_SITE"] # Generate digests for assets URLs config.assets.digest = !!ENV["GENERATING_SITE"] # ... end
  221. Publish a Static Site Using Rails 42 Static::Application.configure do #

    ... # Show full error reports and disable caching config.consider_all_requests_local = true config.action_controller.perform_caching = !!ENV["GENERATING_SITE"] # ... # Don't fallback to assets pipeline if a precompiled asset is missed config.assets.compile = !ENV["GENERATING_SITE"] # Generate digests for assets URLs config.assets.digest = !!ENV["GENERATING_SITE"] # ... end
  222. Publish a Static Site Using Rails 42 class ApplicationController <

    ActionController::Base protect_from_forgery if ENV["GENERATING_SITE"] after_filter do |c| c.cache_page(nil, nil, Zlib::BEST_COMPRESSION) end end end
  223. Publish a Static Site Using Rails 42 class ApplicationController <

    ActionController::Base protect_from_forgery if ENV["GENERATING_SITE"] after_filter do |c| c.cache_page(nil, nil, Zlib::BEST_COMPRESSION) end end end
  224. Publish a Static Site Using Rails 42 require "open-uri" namespace

    :static do desc "Generate a static copy of the site" task :generate => %w[environment assets:precompile] do site = ENV.fetch("RSYNC_SITE_TO") { fail "Must set RSYNC_SITE_TO" } server = spawn( {"GENERATING_SITE" => "true"}, "bundle exec rails s thin -p 3001" ) sleep 10 # FIXME: start when the server is up # ... end
  225. Publish a Static Site Using Rails 42 require "open-uri" namespace

    :static do desc "Generate a static copy of the site" task :generate => %w[environment assets:precompile] do site = ENV.fetch("RSYNC_SITE_TO") { fail "Must set RSYNC_SITE_TO" } server = spawn( {"GENERATING_SITE" => "true"}, "bundle exec rails s thin -p 3001" ) sleep 10 # FIXME: start when the server is up # ... end
  226. Publish a Static Site Using Rails 42 require "open-uri" namespace

    :static do desc "Generate a static copy of the site" task :generate => %w[environment assets:precompile] do # ... # FIXME: improve the following super crude spider paths = %w[/] files = [ ] while path = paths.shift files << File.join("public", path.sub(%r{/\z}, "/index") + ".html") File.unlink(files.last) if File.exist? files.last files << files.last + ".gz" File.unlink(files.last) if File.exist? files.last page = open("http://localhost:3001#{path}") { |url| url.read } page.scan(/<a[^>]+href="([^"]+)"/) do |link| paths << link.first end end # ... end end
  227. Publish a Static Site Using Rails 42 require "open-uri" namespace

    :static do desc "Generate a static copy of the site" task :generate => %w[environment assets:precompile] do # ... # FIXME: improve the following super crude spider paths = %w[/] files = [ ] while path = paths.shift files << File.join("public", path.sub(%r{/\z}, "/index") + ".html") File.unlink(files.last) if File.exist? files.last files << files.last + ".gz" File.unlink(files.last) if File.exist? files.last page = open("http://localhost:3001#{path}") { |url| url.read } page.scan(/<a[^>]+href="([^"]+)"/) do |link| paths << link.first end end # ... end end
  228. Publish a Static Site Using Rails 42 require "open-uri" namespace

    :static do desc "Generate a static copy of the site" task :generate => %w[environment assets:precompile] do # ... system("rsync -a public #{site}") Process.kill("INT", server) Process.wait(server) system("bundle exec rake assets:clean") files.each do |file| File.unlink(file) end end end
  229. Publish a Static Site Using Rails 42 require "open-uri" namespace

    :static do desc "Generate a static copy of the site" task :generate => %w[environment assets:precompile] do # ... system("rsync -a public #{site}") Process.kill("INT", server) Process.wait(server) system("bundle exec rake assets:clean") files.each do |file| File.unlink(file) end end end
  230. Publish a Static Site Using Rails 42 $ rake static:generate

    RSYNC_SITE_TO=/Users/james/Desktop
  231. Publish a Static Site Using Rails 42 $ rake static:generate

    RSYNC_SITE_TO=/Users/james/Desktop
  232. Did you memorize that?!

  233. Did you memorize that?! Slides: http://speakerdeck.com/u/jeg2 Twitter: @JEG2 Email: james@graysoftinc.com

  234. Thanks! Have fun using these Rails tricks