Share
Embed
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.
jeg2
April 25, 2012
Transcript
234 slides
-
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 -
Remind You of Things 3 class UsersController < ApplicationController #
TODO: Make it possible to create new users. end -
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 -
<%# 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 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 -
$ 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 -
<%# 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? -
<%# 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? -
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. -
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. -
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] -
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] -
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] -
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] -
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] -
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" -
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" -
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 -
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 -
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 -
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 -
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 -
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 -
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 -
Understand Shorthand Migrations $ rails g resource user name:string email:string
token:string bio:text 9 From José Valim -
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 -
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 -
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 -
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 -
Add Indexes to Migrations $ rails g resource user name:index
email:uniq token:string{6} bio:text 10 From José Valim -
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 -
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 -
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 -
Add Associations to a Migration $ rails g resource article
user:references subject body:text 11 From José Valim -
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 -
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 -
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 -
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 -
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 -
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 -
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 -
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 -
Import Your CSV Data 13 Name,Email James,[email protected] Dana,[email protected] Summer,[email protected] 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 -
Import Your CSV Data 13 Name,Email James,[email protected] Dana,[email protected] Summer,[email protected] 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 -
Import Your CSV Data 13 Name,Email James,[email protected] Dana,[email protected] Summer,[email protected] 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 -
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 -
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 -
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 -
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 -
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 -
“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" => ["[email protected]", "[email protected]", "[email protected]"] >> User.pluck(:email) (0.2ms) SELECT email FROM "users" => ["[email protected]", "[email protected]", "[email protected]"] >> User.uniq.pluck(:email) (0.2ms) SELECT DISTINCT email FROM "users" => ["[email protected]", "[email protected]", "[email protected]"] -
“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" => ["[email protected]", "[email protected]", "[email protected]"] >> User.pluck(:email) (0.2ms) SELECT email FROM "users" => ["[email protected]", "[email protected]", "[email protected]"] >> User.uniq.pluck(:email) (0.2ms) SELECT DISTINCT email FROM "users" => ["[email protected]", "[email protected]", "[email protected]"] -
“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" => ["[email protected]", "[email protected]", "[email protected]"] >> User.pluck(:email) (0.2ms) SELECT email FROM "users" => ["[email protected]", "[email protected]", "[email protected]"] >> User.uniq.pluck(:email) (0.2ms) SELECT DISTINCT email FROM "users" => ["[email protected]", "[email protected]", "[email protected]"] -
Count Records in Groups 16 $ rails g resource event
article:belongs_to trigger -
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} -
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} -
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} -
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 -
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 -
Instantiate Records Without a Database 18 $ rails c Loading
development environment (Rails 3.2.3) >> User.find(1) => #<User id: 1, name: "James", email: "[email protected]", …> >> jeg2 = User.instantiate("id" => 1, "email" => "[email protected]") => #<User id: 1, email: "[email protected]"> >> 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: "[email protected]", …> -
Instantiate Records Without a Database 18 $ rails c Loading
development environment (Rails 3.2.3) >> User.find(1) => #<User id: 1, name: "James", email: "[email protected]", …> >> jeg2 = User.instantiate("id" => 1, "email" => "[email protected]") => #<User id: 1, email: "[email protected]"> >> 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: "[email protected]", …> -
Instantiate Records Without a Database 18 $ rails c Loading
development environment (Rails 3.2.3) >> User.find(1) => #<User id: 1, name: "James", email: "[email protected]", …> >> jeg2 = User.instantiate("id" => 1, "email" => "[email protected]") => #<User id: 1, email: "[email protected]"> >> 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: "[email protected]", …> -
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 -
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 -
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 -
Use Full Text Search in PostgreSQL 20 $ rails g
resource article subject body:text From PeepCode -
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 -
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 -
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 -
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 -
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 -
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 -
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."] -
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."] -
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."] -
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 -
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 -
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 -
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" -
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 -
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 -
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) ========================= -
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) ========================= -
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) ========================= -
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", …> -
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", …> -
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", …> -
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 -
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 -
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 -
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 -
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 -
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. -
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. -
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}} -
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}} -
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"} -
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"} -
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} -
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} -
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} -
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} -
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 -
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 -
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 -
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 -
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 -
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 -
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 -
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 -
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 -
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 -
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 -
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 -
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 -
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 -
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 -
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 -
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 -
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 -
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 -
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 -
<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 -
<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 -
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 -
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 -
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 %> -
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 %> -
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 %> -
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 %> -
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 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 %> -
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 %> -
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 %> -
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] ) ) %> -
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] ) ) %> -
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 -
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 -
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 -
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 -
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 -
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 -
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 -
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 %> -
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 %> -
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> <!-- ... --> -
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> <!-- ... --> -
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> <!-- ... --> -
Route Exceptions From José Valim 38 # ... module Blog
class Application < Rails::Application # ... config.exceptions_app = routes end end -
Route Exceptions From José Valim 38 # ... module Blog
class Application < Rails::Application # ... config.exceptions_app = routes end end -
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 -
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 -
Route to Sinatra From Crafting Rails Applications 39 source 'https://rubygems.org'
# ... gem "resque", require: "resque/server" -
Route to Sinatra From Crafting Rails Applications 39 source 'https://rubygems.org'
# ... gem "resque", require: "resque/server" -
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 -
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 -
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 -
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 -
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 -
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 -
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 -
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 -
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 -
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 -
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 -
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 -
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 -
Do Some Work in the Background From Crafting Rails Applications
41 $ rails g migration add_stats_to_articles stats:text -
Do Some Work in the Background From Crafting Rails Applications
41 $ rails g migration add_stats_to_articles stats:text -
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 -
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 -
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 -
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 -
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 -
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 -
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 -
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 -
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 -
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"] -
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"] -
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"] -
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 -
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 -
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 -
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 -
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 -
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 -
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 -
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 -
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 -
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 -
Publish a Static Site Using Rails 42 $ rake static:generate
RSYNC_SITE_TO=/Users/james/Desktop -
Publish a Static Site Using Rails 42 $ rake static:generate
RSYNC_SITE_TO=/Users/james/Desktop