The Rails Way
Upcoming SlideShare
Loading in...5
×
 

The Rails Way

on

  • 2,713 views

 

Statistics

Views

Total Views
2,713
Views on SlideShare
2,713
Embed Views
0

Actions

Likes
2
Downloads
20
Comments
0

0 Embeds 0

No embeds

Accessibility

Categories

Upload Details

Uploaded via as Adobe PDF

Usage Rights

© All Rights Reserved

Report content

Flagged as inappropriate Flag as inappropriate
Flag as inappropriate

Select your reason for flagging this presentation as inappropriate.

Cancel
  • Full Name Full Name Comment goes here.
    Are you sure you want to
    Your message goes here
    Processing…
Post Comment
Edit your comment

The Rails Way The Rails Way Presentation Transcript

  • The Rails WayApproach to modern web applications with Rails 3.2
  • The Performance Golden Rule80% of end-users response time isdownloading all the assets.
  • The Rails Way to managingassets: HTTP Streaming The Assets Pipeline
  • Assets Pipeline● Assets concatenation● Assets minification● Support for high-level languages ○ CoffeeScript ○ SASS● Assets fingerprinting
  • Syntactically Awesome Stylesheets$blue: #3bbfce;$margin: 16px;.content-navigation { border-color: $blue; color: darken($blue, 9%);}.border { padding: $margin / 2; margin: $margin / 2; border-color: $blue;}
  • CoffeeScriptclass ProfileCompetences extends Backbone.View tagName: ul className: inputs-select initialize: -> @collection.on(reset, @render, this) render: -> competences = @collection.competences() _.each competences, (competence) => view = new AutosaveSelectOption(model: @model, dict: competence) $(@el).append(view.render().el) this
  • Serving Static Assets Rails by default doesnt serve static assets in production environment.
  • Deploymentict-ref-cloud/ current -> ~/ict-ref-cloud/releases/20120904134910 releases/ 20120904134910/ app/ config/ database.yml -> ~/ict-ref-cloud/shared/config/database.yml public/ assets -> ~/ict-ref-cloud/shared/assets shared/ assets/ application-8e3bd046319a574dc48990673b1a4dd9.js application-8e3bd046319a574dc48990673b1a4dd9.js.gz application.css application.css.gz config/ database.yml
  • Deployment nginx ~/ict-ref-cloud/current/public/tmp/unicorn.ict-ref-cloud.sock unicorn ~/ict-ref-cloud/current
  • OWASP Top Ten Security Risk 1. Injection 2. Cross Site Scripting 3. Broken Authentication and Session Management 4. Insecure Direct Object Reference 5. Cross Site Request Forgery 6. Security Misconfiguration 7. Insecure Cryptographic Storage 8. Failure To Restrict URL Access 9. Insufficient Transport Layer Protection10. Unvalidated Redirects and Forwards
  • OWASP Top Ten Security Risk 1. Injection 2. Cross Site Scripting 3. Broken Authentication and Session Management 4. Insecure Direct Object Reference 5. Cross Site Request Forgery 6. Security Misconfiguration 7. Insecure Cryptographic Storage 8. Failure To Restrict URL Access 9. Insufficient Transport Layer Protection10. Unvalidated Redirects and Forwards Problems related specifically to view layer.
  • The Rails Way to security: CSRF protection XSS protection
  • Cross Site Request Forgery/app/controllers/application_controller.rbclass ApplicationController < ActionController::Base protect_from_forgeryend/app/views/layouts/application.html.erb<head> <%= csrf_meta_tags %></head><meta content="authenticity_token" name="csrf-param"><meta content="KklMulGyhEfVztqfpMn5nRYc7zv+tNYb3YovBwOhTic=" name="csrf-token">
  • Cross Site Scripting<div id="comments"> <% @post.comments.each do |comment| %> <div class="comment"> <h4><%= comment.author %> says:</h4> <p><%= comment.content %></p> </div> <% end %></div><%# Insecure! %><%= raw product.description %>
  • The Rails Way to routing: Non-Resourceful routes Resourceful routes SEO friendly URLs
  • Non-Resourceful Routesmatch products/:id => products#showGET /products/10post products => products#createPOST /productsnamespace :api do put products/:id => api/products#updateendPUT /api/products/10
  • Non-Resourceful Routesmatch photos/show => photos#show, :via => [:get, :post]match photos/:id => photos#show, :constraints => { :id => /[A-Z]d{5}/ }match "photos", :constraints => { :subdomain => "admin" }match "/stories/:name" => redirect("/posts/%{name}")match books/*section/:title => books#showroot :to => pages#main
  • Resourceful Routesresources :photosget /photos => photos#indexget /photos/new => photos#newpost /photos => photos#createget /photos/:id => photos#showget /photos/:id/edit => photos#editput /photos/:id => photo#updatedelete /photos/:id => photo#destroy
  • Resourceful Routesresource :profileget /profile/new => profiles#newpost /profile => profiles#createget /profile => profiles#showget /profile/edit => profiles#editput /profile => profile#updatedelete /profile => profile#destroy
  • Named Routes<%= link_to Profile, profile_path %>=> <a href="/profile">Profile</a><%= link_to Preview, @photo %>=> <a href="/photo/10">Preview</a>
  • SEO Friendy URLs <%= link_to product.name, product %> Will generate /products/14-foo-bar /products/14-foo-bar "/products/:id" => "products#show" { :id => "14-foo-bar" } class Product < ActiveRecord::Base def to_param "#{id}-#{name.parametrize}" end Product.find(params[:id]) end Will call to_i Product.find(14)Example from: http://www.codeschool.com/courses/rails-best-practices
  • The Rails Way to viewrendering: Response rendering Structuring Layouts AJAX
  • Response Rendering/app /app /controllers /views products_controller.rb /products users_controller.rb index.html.erb show.html.erb /users index.html.erb new.html.erb
  • Response Renderingclass UsersController < ApplicationController def new @user = User.new new.html.erb end def create @user = User.new(params[:user]) if @user.save redirect_to :action => :show show.html.erb else render :new new.html.erb end endend
  • Rendering Responserender :editrender :action => :editrender editrender edit.html.erbrender :template => products/editrender products/editrender :file => /path/to/filerender /path/to/file
  • Rendering Responserender :inline => <p><%= @comment.content %></p>render :text => OKrender :json => @productrender :xml => @productrender :js => "alert(Hello Rails);"render :status => 500render :status => :forbiddenrender :nothing => true, :status => :created
  • Content Negotiationrespond_to do |format| format.html format.json { render :json => @product } format.jsend
  • Content Negotiationclass ProductsController < ApplicationController respond_to :html, :json, :js def edit respond_with Product.find(params[:id]) end def update respond_with Product.update(params[:id], params[:product]) endend
  • Structuring Layout/app /views /layouts application.html.erb (default) users.html.erb (UsersController) public.html.erb (layout public)
  • Structuring Layout<!DOCTYPE html><head> <title>User <%= yield :title %></title></head><html> <body> <%= yield %> </body></html>
  • Structuring Layout<% content_for :title, @post.title %><div id="post"> <h2><%= @post.title %></h2> <div><%= @post.content %></div></div>
  • View Helpersmodule ApplicationHelper def title(title) content_for :title, title endend
  • View Helpers<% title @post.title %><div id="post"> <h2><%= @post.title %></h2> <div><%= @post.content %></div></div>
  • Partials/app /views /products _form.html.erb _product.html.erb index.html.erb edit.html.erb new.html.erb
  • Partials/app/views/products/_product.html.erb<div class="product"> <h2><%= product.name %></h2> <p><%= product.description %></p></div> Partial parameter
  • Partials<h1>Products</h1><% @products.each do |product| %> <% render products/product, :product => product %><% end %>
  • Partials<h1>Products</h1><% @products.each do |product| %> <% render product %><% end %>
  • Partials<h1>Products</h1><% render @products %>
  • Partials/app/views/products/_form.html.erb<%= form_for @user do |f| %> <div class="input"> <%= f.label :name %> <%= f.text_field :name %> </div> <div class="input"> <%= f.label :description %> <%= f.text_area :description %> </div> <div class="actions"> <%= f.submit %> </div><% end %>
  • Partials../products/new.html.erb ../products/edit.html.erb<h1>New Product</h1> <h1>Edit Product</h1><div id="form"> <div id="form"> <% render form %> <% render form %></div> </div>
  • AJAX/app/views/products/_form.html.erb<%= form_for @user, :remote => true do |f| %> <div class="input"> <%= f.label :name %> <%= f.text_field :name %> </div> <div class="input"> <%= f.label :description %> <%= f.text_area :description %> </div> <div class="actions"> <%= f.submit %> </div><% end %>
  • AJAX/app/controllers/products_controller.rbclass ProductsController < ApplicationController def create @product = Product.new(params[:product]) respond_to do |format| if @product.save format.html { redirect_to @product } else format.html { render :action => new } format.js end end endend
  • AJAX/app/views/products/create.js.erb$(#form).html("<%= escape_javascript(render form) %>");
  • AJAX/app/views/products/index.html.erb<%= link_to "Delete", product, method: :delete, remote: true %><a href="/products/1" data-method="delete" data-remote="true" rel="nofollow">Delete</a> (Rails is using unobtrusive javascript technique)/app/views/products/destroy.js.erb$("#<%= dom_id @product %>").fadeOut();
  • The Rails Way to caching: Basic Caching Memoization
  • Page Cachingclass ProductsController < ActionController caches_page :index def index @products = Product.all end def create expire_page :action => :index endendPage caching wont work with filters.
  • Action Cachingclass ProductsController < ActionController before_filter :authenticate_user! caches_action :index def index @products = Product.all end def create expire_action :action => :index endend
  • Fragment Caching<% cache do %> All available products: <% @products.each do |p| %> <%= link_to p.name, product_url(p) %> <% end %><% end %>expire_fragment( :controller => products, :action => recent, :action_suffix => all_products)
  • Sweepersclass ProductSweeper < ActionController::Caching::Sweeper observe Product def after_create(product) # Expire the index page now that we added a new product expire_page(:controller => products, :action => index) # Expire a fragment expire_fragment(all_available_products) endend
  • Conditional GET supportclass ProductsController < ApplicationController def show @product = Product.find(params[:id]) if stale?(:last_modified => @product.updated_at.utc, :etag => @product) respond_to do |format| # ... normal response processing end end endend
  • Memoizationclass City < ActiveRecord::Base attr_accesible :name, :zip, :lat, :lon def display_name @display_name ||= "#@zip #@name" endend
  • The Rails Way to solvetypical problems: N+1 Problem Fetching object in batches
  • N+1 Problemclass User def recent_followers self.followers.recent.collect do |f| f.user.name end endendSelect followers where user_id=1 Select user where id=2 Select user where id=3 Select user where id=4 Select user where id=5Source: http://www.codeschool.com/courses/rails-best-practices
  • N+1 Problemclass User def recent_followers self.followers.recent.includes(:user).collect do |f| f.user.name end endendSelect followers where user_id=1 Select users where user_id in (2,3,4,5)Bullet Gem:https://github.com/flyerhzm/bulletSource: http://www.codeschool.com/courses/rails-best-practices
  • Fetching objects in JavaList<Tweet> tweets = tweetDao.findAllForUser(user);for (Tweet tweet : tweets) { // ...}for (Tweet tweet : user.getTweets()) { // ...}
  • Fetching objects in RailsTweet.where(user: user).find_each do |tweet| # ...enduser.tweets.find_each(batch_size: 5000) do |tweet| # ...endBy default pulls batches of 1,000 at a time
  • Try Rails!