ruby on rails 101
TRANSCRIPT
1.9.2
3.0.5
RubyonRails 101
@claytonlz - Desert Code Camp 2011.1 - http://spkr8.com/t/7007
Saturday, April 2, 2011
EcosystemModelsControllersViewsDeploying & OptimizingResources for Learning
Saturday, April 2, 2011
Community
Saturday, April 2, 2011
“This sure is a nice fork, I bet I could… HOLY
SHIT A KNIFE!”
Saturday, April 2, 2011
Opinionated
Saturday, April 2, 2011
“I flippin’ told you MVCis the only way to buildweb apps! Teach you to
doubt DHH!”
Saturday, April 2, 2011
Rapid Development
Saturday, April 2, 2011
“These goats are okay, but I really need a yak
for some quality shaving”
Saturday, April 2, 2011
EcosystemModelsControllersViewsDeployingResources for Learning
Saturday, April 2, 2011
Models
AssociationsValidationsCallbacksQuerying
Saturday, April 2, 2011
Models
ActiveRecord::Baseclass Product < ActiveRecord::Base ...end
productsproductsname string
sku string
price decimal
Saturday, April 2, 2011
Models ➤ Associations# manufacturerhas_many :products
# producthas_one :upcbelongs_to :manufacturerhas_many :batcheshas_many :ingredients, :through => :batches
# batchbelongs_to :productbelongs_to :ingredient
# ingredienthas_many :batcheshas_many :products, :through => :batches
products
manufacturersupcs
batches
ingredients
Saturday, April 2, 2011
Models ➤ Associations
# create a product and find its manufacturerproduct = manufacturer.products.create({:name => "Kitlifter"})product.manufacturer
# create a upc and find its product's manufacturerupc = product.create_upc({:code => "001122"})upc.product.manufacturer
# create a batch (linking a product and ingredient)wheat = Ingredient.create({:name => "Wheat"})bread = Product.create({:name => "Bread"})
batch.create({:product => bread, :ingredient => wheat})
Saturday, April 2, 2011
Models ➤ Associations
“Using has_many or belongs_to is more than just on which table the foreign key is placed,
itʼs a matter of who can be thought of as ʻowningʼ the other. A product ʻownsʼ a UPC.”
When should I use has_oneand belongs_to?
Saturday, April 2, 2011
Models ➤ Validations
class Product < ActiveRecord::Base validates_presence_of :name validates_uniqueness_of :name validates_format_of :sku, :with => /^SKU\d{8}$/ validates_inclusion_of :usda_rating, :in => %w( prime choice ) validate :cannot_be_active_if_recalled def cannot_be_active_if_recalled if recalled? && recalled_on < Date.today errors.add(:active, "Can't be active if it's been recalled") endend
Saturday, April 2, 2011
Models ➤ Validations
“It is possible to save a record, without validating, by using save(:validate => false)”
I know my record istechnically invalid, butI want to save it anyhow.
Saturday, April 2, 2011
Models ➤ Callbacks
class Ingredient before_destroy :determine_destroyability before_create :format_legacy_name after_update :log_changes after_create :import_harvest_data # validation # create # save # update # destroy end
Callback Chain
STOP!!
determine_destroyability
Saturday, April 2, 2011
Models ➤ Querying
Product.find(98)Product.find_by_name("Diet Coke")Product.find_by_name_and_sku("Diet Coke", "SKU44387")Product.find([98,11,39])Product.firstProduct.lastProduct.allProduct.count
# old and bustedProduct.find(:all, :conditions => {:name => "Cheese-it!"})
# new hotnessProduct.where(:name => "Cheese-it!").all
Saturday, April 2, 2011
Models ➤ QueryingProduct.where("name = ?", 'Skittles')Product.where(:created_at => Date.yesterday..Date.today)Product.where(:sku => ["SKU912", "SKU187", "SKU577"])
Product.order('name DESC')
Product.select('id, name')
Product.limit(5)
# chainableProduct.where(:created_at => Date.yesterday..Date.today) .limit(10) Product.order('created_at ASC').limit(20).offset(40)
Product.select('created_at').where(:name => 'Twix')
Saturday, April 2, 2011
Models ➤ Queryingmanufacturer.includes(:products) .where('products.usda_rating = ?', 'prime')
manufacturer.includes(:products) .where(:state => 'AZ') .order('created_at') manufacturer.includes(:products => :ingredients) .where('ingredients.name = ?', 'glucose') .order('updated_at') manufacturer.joins(:products) .where('products.sku = ?', 'SKU456') ingredient.includes(:products => {:manufacturer => :conglomerate}) .where('conglomerates.name = ?', 'nestle') animalia.includes(:phylum => {:class => {:order => {:family => :genus}}})
child.includes(:parent => [:brother, {:sister => :children}])
Saturday, April 2, 2011
Models ➤ Validations
“Using includes will load the records into memory when the query
is executing, joins will not.”
Why would I use joinsinstead of includes?
Saturday, April 2, 2011
Controllers
RoutingFiltersConventions
Saturday, April 2, 2011
Controllers ➤ Routingresources :products# GET /products => index action# GET /products/new => new action# GET /products/:id => show action# GET /products/:id/edit => edit action## POST /products => create action# # PUT /products/:id => update action## DELETE /products/:id => destroy action
products_path # /productsproducts_url # http://www.example.com/products
product_path(@product) # /products/29product_path(@product, :xml) # /products/29.xml
Saturday, April 2, 2011
Controllers ➤ Routing
namespace :admin do resources :users resources :ordersend
admin_users_path # /admin/usersedit_admin_order_path # /admin/orders/4/edit
class Admin::UsersController < ApplicationController # /app/controllers/admin/users_controller.rb # /app/views/admin/users/end
Saturday, April 2, 2011
Controllers ➤ Routingresources :accounts, :except => :destroy do resources :users do post :activate, :on => :member collection do get 'newest' end end resources :clients, :only => [:index, :show]end
account_users_path(@account) # /accounts/182/usersnewest_account_users_path(@account) # /accounts/182/users/newestactivate_account_user_path(@account, @user) # /accounts/182/user/941
accounts_clients_path(@account) # /accounts/182/clientsnew_accounts_client_path(@account) # FAIL!
Saturday, April 2, 2011
Controllers ➤ Filters
class UsersController < ApplicationController before_filter :load_manufacturer before_filter :find_geo_data, :only => [:show] skip_before_filter :require_login after_filter :log_accessend
# in ApplicationControllerdef log_access Rails.logger.info("[Access Log] Users Controller access at #{Time.now}")end
Saturday, April 2, 2011
Controllers ➤ Conventionsclass ProductsController < ApplicationController def index # GET /products end def show # GET /products/:id end def new # GET /products/new end def create # POST /products end def edit # GET /products/:id/edit end def update # PUT /products/:id end def destroy # DELETE /products/:id endend
def update # ... update occurred @parent.children.each ...end
def edit @product = Product.find(params[:id])end
def show @product = Product.find(params[:id])end
def destroy @product = Product.find(params[:id])end
before_filter :load_product
☹
☹
☺
Saturday, April 2, 2011
Controllers ➤ Conventionsclass ProductsController < ApplicationController def index # GET /products end def show # GET /products/:id # renders /app/views/products/show.format end def new # GET /products/new end def create # POST /products redirect_to products_url end def edit # GET /products/:id/edit end def update # PUT /products/:id end def destroy # DELETE /products/:id endend
def update # ... update occurred @parent.children.each ...end
def edit @product = Product.find(params[:id])end
def show @product = Product.find(params[:id])end
def destroy @product = Product.find(params[:id])end
before_filter :load_product
☹
☹
☺
☞
☞
Saturday, April 2, 2011
Views
Layouts & HelpersFormsPartialsActionView Helpers
Saturday, April 2, 2011
Views ➤ Layouts & Helpers
<!-- app/views/products/show.html.erb --><h2><%= @product.name %></h2><p>Price: <%= @product.price %></p>
<!-- app/layouts/application.html.erb --><div id="container"> <%= yield %></div>
<div id="container"> <h2>Pop-Tarts</h2> <p>Price: $3.99</p></div>
def show @product = Product.find(params[:id])end M C
V
Saturday, April 2, 2011
Views ➤ Layouts & Helpers<h2><%= @product.name %></h2><p>Price: <%= number_to_currency(@product.price) %></p><p>Ingredients: <%= @product.ingredients.present? ? @product.ingredients.map(&:name).join(',') : 'N/A' %></p>
# app/helpers/products_helper.rbdef display_ingredients(ingredients) return "N/A" if ingredients.blank? ingredients.map(&:name).join(',')end
<h2><%= @product.name %></h2><p>Price: <%= number_to_currency(@product.price) %></p><p>Ingredients: <%= display_ingredients(@product.ingredients) %></p>
Saturday, April 2, 2011
Views ➤ Forms
<%= form_tag search_path do %> <p> <%= text_field_tag 'q' %><br /> <%= submit_tag('Search') %> </p><% end %>
<form action="/search" method="post"> <p> <input type="text" name="q" value="" id="q" /> <input type="submit" name="commit_search" value="Search" id="commit_search" /> </p></form>
Saturday, April 2, 2011
Views ➤ Forms<h2>New Product</h2><%= form_for(@product) do |f| %> <!-- action => /products/:id --> <!-- method => POST --> <p> <%= f.text_field :name %> </p> <p> <%= f.check_box :active %> </p><% end %>
<h2>Edit Product</h2><%= form_for(@product) do |f| %> <!-- action => /products/:id --> <!-- method => PUT --> <p> <%= f.text_field :name %> </p> <p> <%= f.check_box :active %> </p><% end %>
← New Record
Existing Record →
Saturday, April 2, 2011
Views ➤ Forms
<%= f.hidden_field :secret %><%= f.password_field :password %><%= f.label :name, "Product Name" %><%= f.radio_button :style, 'Clear' %><%= f.text_area, :description %><%= f.select :condition, ["Good", "Fair", "Bad"] %>
<%= f.email_field :user_email %><%= f.telephone_field :cell_number %>
Saturday, April 2, 2011
Views ➤ Partials
<% @products.each do |product| %> <tr><td><%= link_to(product.title, product_path(product)) %></td></tr><% end %>
<% @products.each do |product| %> <%= render :partial => 'product_row', :locals => {:product => product} %><% end %>
<!-- app/views/products/_product_row.html.erb --><tr><td><%= link_to(product.title, product_path(product)) %></td></tr>
<%= render :partial => 'product_row', :collection => @products, :as => :product %>
Saturday, April 2, 2011
Views ➤ Partials
<!-- app/views/shared/_recent_changes.html.erb --><ul> <li>...</li> <li>...</li></ul>
<!-- app/views/reports/index.html.erb --><%= render :partial => 'shared/recent_changes' %>
<!-- app/views/pages/news.html.erb --><%= render :partial => 'shared/recent_changes' %>
<%= render :partial => @product %><%= render(@product) %>
<%= render 'bio', :person => @john %>
Saturday, April 2, 2011
Views ➤ Partials
NumberHelperTextHelperFormHelperJavaScriptHelperDateHelperUrlHelperCaptureHelperSanitizeHelper
Saturday, April 2, 2011
Deploying & Optimizing
Heroku
NewRelicPassenger
Saturday, April 2, 2011
Resources for Learning
Video
PeepCode
RailsCasts
CodeSchool
Books
The Rails Way
Beginning Ruby
Ruby for _________Other
PHX Rails User Group
Gangplank
Saturday, April 2, 2011
@claytonlzhttp://spkr8.com/t/7007
Saturday, April 2, 2011