Action Controller Overview, Season 2

53
Action Controller Overview Ror lab. season 2 - the 15th round - February 2th, 2013 Hyoseong Choi
  • date post

    12-Sep-2014
  • Category

    Education

  • view

    2.601
  • download

    0

description

 

Transcript of Action Controller Overview, Season 2

Page 1: Action Controller Overview, Season 2

Action ControllerOverview

Ror lab. season 2- the 15th round -

February 2th, 2013

Hyoseong Choi

Page 2: Action Controller Overview, Season 2

A Controller

• RESTful applications

• like an orchestra conductor

• as a middle man btw models and views

Page 3: Action Controller Overview, Season 2

REST

GET /books HTTP/1.1Host: rorlab.orgAccept: application/xml

#index

POST /books HTTP/1.1Host: rorlab.orgAccept: application/xml

#create

GET /books/1 HTTP/1.1Host: rorlab.orgAccept: application/xml

#show

PUT /books/1 HTTP/1.1Host: rorlab.orgAccept: application/xml

#update

GET /books/new HTTP/1.1Host: rorlab.orgAccept: application/xml

#new

DELETE /books/1 HTTP/1.1Host: rorlab.orgAccept: application/xml

#destroy

GET /books/1/edit HTTP/1.1Host: rorlab.orgAccept: application/xml

#edit

URI with HTTP methods

Page 4: Action Controller Overview, Season 2

URI?

• Uniform Resource Identifier= URL + URN= Uniform Resource Locator + Uniform Resource Name

http://domain_name/posts/114

Page 5: Action Controller Overview, Season 2

Routing

$ rake routes CONTROLLER=books

books GET /books(.:format) books#index

POST /books(.:format) books#create new_book GET /books/new(.:format) books#new

edit_book GET /books/:id/edit(.:format) books#edit

book GET /books/:id(.:format) books#show

PUT /books/:id(.:format) books#update

DELETE /books/:id(.:format) books#destroy

named routes

HTTPverbs

resourceURI

ControllersActions

Page 6: Action Controller Overview, Season 2

MVC

Page 7: Action Controller Overview, Season 2

MVC

View Model

Controller

Page 8: Action Controller Overview, Season 2

Methods & Actions

• A “class” has methods

• A controller < ApplicationController

• public methods => “action” <= routing

$ rake routes CONTROLLER=clients

clients GET /clients(.:format) clients#index POST /clients(.:format) clients#create new_client GET /clients/new(.:format) clients#newedit_client GET /clients/:id/edit(.:format) clients#edit client GET /clients/:id(.:format) clients#show PUT /clients/:id(.:format) clients#update DELETE /clients/:id(.:format) clients#destroy

actions

Page 9: Action Controller Overview, Season 2

Parameters• Two kinds of parameters

- Query string

- POST data

• by params hash for both of these

• “Routing” parameters

Page 10: Action Controller Overview, Season 2

Hash & Array Params

GET /clients?ids[]=1&ids[]=2&ids[]=3

params[:ids] ?

[ “1”, “2”, “3”]

for Query String

Page 11: Action Controller Overview, Season 2

Hash & Array Params

<form accept-charset="UTF-8" action="/clients" method="post">  <input type="text" name="client[name]" value="Acme" />  <input type="text" name="client[phone]" value="12345" />  <input type="text" name="client[address][postcode]" value="12345" />  <input type="text" name="client[address][city]" value="Carrot City" /></form>

for POST data

params[:client] ?

{ “name” => “Acme”, “phone” => “12345”, “address” => { “postcode” => “12345”, “city” => “Carrot City” }}

Page 12: Action Controller Overview, Season 2

JSON/XML Params

{ "company": { "name": "acme", "address": "123 Carrot Street" } }

JSON parameter

automatically converted to params hash by Rails

{ :name => “acme”, “address” => “123 Carrot Street” }

params[:company]

Page 13: Action Controller Overview, Season 2

default_url_options

➙ global default parameter

class PostsController < ApplicationController  # The options parameter is the hash passed in to 'url_for'  def default_url_options(options)    {:locale => I18n.locale}  endend

Page 14: Action Controller Overview, Season 2

url_for<%= url_for(:action => 'index') %># => /blog/

<%= url_for(:action => 'find', :controller => 'books') %># => /books/find

<%= url_for(:action => 'login', :controller => 'members', :only_path => false, :protocol => 'https') %># => https://www.example.com/members/login/

<%= url_for(:action => 'play', :anchor => 'player') %># => /messages/play/#player

<%= url_for(:action => 'jump', :anchor => 'tax&ship') %># => /testing/jump/#tax&ship

<%= url_for(Workshop.new) %># relies on Workshop answering a persisted? call (and in this case returning false)# => /workshops

<%= url_for(@workshop) %># calls @workshop.to_param which by default returns the id# => /workshops/5

# to_param can be re-defined in a model to provide different URL names:# => /workshops/1-workshop-name

<%= url_for("http://www.example.com") %># => http://www.example.com

<%= url_for(:back) %># if request.env["HTTP_REFERER"] is set to "http://www.example.com"# => http://www.example.com

<%= url_for(:back) %># if request.env["HTTP_REFERER"] is not set or is blank# => javascript:history.back()

Page 15: Action Controller Overview, Season 2

Session

• ActionDispatch::Session::CookieStore

• ActionDispatch::Session::CacheStore

• ActionDispatch::Session:: ActiveRecordStore

• ActionDispatch::Session::MemCacheStore

stateless ➤ stateful in controllers

Session Repositories :

Page 16: Action Controller Overview, Season 2

class LoginsController < ApplicationController  # "Create" a login, aka "log the user in"  def create    if user = User.authenticate(params[:username], params[:password])      # Save the user ID in the session so it can be used in      # subsequent requests      session[:current_user_id] = user.id      redirect_to root_url    end  endend

SessionAccessing the Session

lazily loaded

Page 17: Action Controller Overview, Season 2

class LoginsController < ApplicationController  # "Delete" a login, aka "log the user out"  def destroy    # Remove the user id from the session    @_current_user = session[:current_user_id] = nil    redirect_to root_url  endend

SessionRemoving a Session Key

cf. reset_session

Page 18: Action Controller Overview, Season 2

Session

• special session : Hash

• cleared with each request

• only available in the next request

• useful for storing error messages etc

Flasha disposable session

Page 19: Action Controller Overview, Season 2

redirect_to root_url, notice: "You have successfully logged out."redirect_to root_url, alert: "You're stuck here!"redirect_to root_url, flash: { referral_code: 1234 }

SessionFlash

Page 20: Action Controller Overview, Season 2

<html>  <!-- <head/> -->  <body>    <% flash.each do |name, msg| -%>      <%= content_tag :div, msg, class: name %>    <% end -%>     <!-- more content -->  </body></html>

SessionFlash

Page 21: Action Controller Overview, Season 2

<% if flash[:just_signed_up] %>  <p class="welcome">Welcome to our site!</p><% end %>

SessionFlash

Page 22: Action Controller Overview, Season 2

class MainController < ApplicationController  # Let's say this action corresponds to root_url, but you want  # all requests here to be redirected to UsersController#index.  # If an action sets the flash and redirects here, the values  # would normally be lost when another redirect happens, but you  # can use 'keep' to make it persist for another request.  def index    # Will persist all flash values.    flash.keep     # You can also use a key to keep only some kind of value.    # flash.keep(:notice)    redirect_to users_url  endend

SessionFlash

flash.keep

Page 23: Action Controller Overview, Season 2

class ClientsController < ApplicationController  def create    @client = Client.new(params[:client])    if @client.save      # ...    else      flash.now[:error] = "Could not save client"      render :action => "new"    end  endend

SessionFlash

flash.now

Page 24: Action Controller Overview, Season 2

Cookies• persisted across request and even sessions

class CommentsController < ApplicationController  def new    # Auto-fill the commenter's name if it has been stored in a cookie    @comment = Comment.new(:name => cookies[:commenter_name])  end   def create    @comment = Comment.new(params[:comment])    if @comment.save      flash[:notice] = "Thanks for your comment!"      if params[:remember_name]        # Remember the commenter's name.        cookies[:commenter_name] = @comment.name      else        # Delete cookie for the commenter's name cookie, if any.        cookies.delete(:commenter_name)      end      redirect_to @comment.article    else      render :action => "new"    end  endend

Page 25: Action Controller Overview, Season 2

• to delete a cookie value

cookies.delete(:key)

Cookies

Page 26: Action Controller Overview, Season 2

xml & json data

class UsersController < ApplicationController  def index    @users = User.all    respond_to do |format|      format.html # index.html.erb      format.xml  { render :xml => @users}      format.json { render :json => @users}    end  endend

Page 27: Action Controller Overview, Season 2

Filters

Actionbefore after

around

methods inherited

not to halt actionto halt action

Page 28: Action Controller Overview, Season 2

Filtersclass ApplicationController < ActionController::Base  before_filter :require_login   private   def require_login    unless logged_in?      flash[:error] = "You must be logged in to access this section"      redirect_to new_login_url # halts request cycle    end  end   # The logged_in? method simply returns true if the user is logged  # in and false otherwise. It does this by "booleanizing" the  # current_user method we created previously using a double ! operator.  # Note that this is not common in Ruby and is discouraged unless you  # really mean to convert something into true or false.  def logged_in?    !!current_user  endend

booleanizing operator

Page 29: Action Controller Overview, Season 2

Filters

class LoginsController < ApplicationController  skip_before_filter :require_login, :only => [:new, :create]end

• skip_before_filter

Page 30: Action Controller Overview, Season 2

Filters

class ChangesController < ActionController::Base  around_filter :wrap_in_transaction, :only => :show   private   def wrap_in_transaction    ActiveRecord::Base.transaction do      begin        yield      ensure        raise ActiveRecord::Rollback      end    end  endend

• around_filter

Page 31: Action Controller Overview, Season 2

Filters

• Three Ways to use Filters

- a private method

- a block

- a class

Page 32: Action Controller Overview, Season 2

Filters• Using a Block in more simple cases

class ApplicationController < ActionController::Base  before_filter do |controller|    redirect_to new_login_url unless controller.send(:logged_in?)  endend

Page 33: Action Controller Overview, Season 2

Filters• Using a Class in more complex cases

class ApplicationController < ActionController::Base  before_filter LoginFilterend class LoginFilter  def self.filter(controller)    unless controller.send(:logged_in?)      controller.flash[:error] = "You must be logged in"      controller.redirect_to controller.new_login_url    end  endend

Page 34: Action Controller Overview, Season 2

CSRF

• Site to site hacking

• First step for this:create/update/destroy with non-GET request

• RESTful default to protect CSRF

• Nevertheless, non-GET request still vulnerable

Page 35: Action Controller Overview, Season 2

CSRF• To add a non-guessable token with form helpers

<%= form_for @user do |f| %>  <%= f.text_field :username %>  <%= f.text_field :password %><% end %>

<form accept-charset="UTF-8" action="/users/1" method="post"><input type="hidden"       value="67250ab105eb5ad10851c00a5621854a23af5489"       name="authenticity_token"/><!-- fields --></form>

Page 36: Action Controller Overview, Season 2

CSRF• form_authenticity_token in custom Ajax calls

Page 37: Action Controller Overview, Season 2

Request & Response Objects

• Two methods in every controller

- `request` method => request object

- `response` method => response object

Page 38: Action Controller Overview, Season 2

Request Objects

Page 39: Action Controller Overview, Season 2

Request Objects

• Three hash parameters for request objects

- path_parameters

- query_parameters : query string

- request_parameters : post data

Page 40: Action Controller Overview, Season 2

Response Objects

• like in an `after` filter

Page 41: Action Controller Overview, Season 2

Response Objects

response.headers["Content-Type"] = "application/pdf"

Page 42: Action Controller Overview, Season 2

HTTP Authentications

Page 43: Action Controller Overview, Season 2

HTTP Authentications

• Two types

- Basic authentication : using base 64 encoding

- Digest authentication: using MD5 encoding

Page 44: Action Controller Overview, Season 2

HTTP Authentications• Basic authentication

class AdminController < ApplicationController  http_basic_authenticate_with :name => "humbaba", :password => "5baa61e4"end

Page 45: Action Controller Overview, Season 2

HTTP Authentications• Digest authentication

class AdminController < ApplicationController  USERS = { "lifo" => "world" }   before_filter :authenticate   private   def authenticate    authenticate_or_request_with_http_digest do |username|      USERS[username]    end  endend

Safari v 6.0.2undefined method `unpack' for nil:NilClass

Page 46: Action Controller Overview, Season 2

Streaming & File Downloads

require "prawn"class ClientsController < ApplicationController  # Generates a PDF document with information on the client and  # returns it. The user will get the PDF as a file download.  def download_pdf    client = Client.find(params[:id])    send_data generate_pdf(client),              :filename => "#{client.name}.pdf",              :type => "application/pdf", :disposition => "attachement"  end   private   def generate_pdf(client)    Prawn::Document.new do      text client.name, :align => :center      text "Address: #{client.address}"      text "Email: #{client.email}"    end.render  endend

send_data

•send_data•send_file

Page 47: Action Controller Overview, Season 2

Streaming & File Downloads

class ClientsController < ApplicationController  # Stream a file that has already been generated and stored on disk.  def download_pdf    client = Client.find(params[:id])    send_file("#{Rails.root}/files/clients/#{client.id}.pdf",              :filename => "#{client.name}.pdf",              :type => "application/pdf")  endend

send_file

Page 48: Action Controller Overview, Season 2

Streaming & File Downloads

send_file

in a

RES

Tful

app

licat

ion

require "prawn"class ClientsController < ApplicationController   def show    @client = Client.find(params[:id])     respond_to do |format|      format.html      format.pdf { render :pdf => generate_pdf(@client) }    end  end

  private   def generate_pdf(client)    Prawn::Document.new do      text client.name, :align => :center      text "Address: #{client.address}"      text "Email: #{client.email}"    end.render  endend

#153(revised)

Page 49: Action Controller Overview, Season 2

Streaming & File Downloads

send_file

in a

RES

Tful

app

licat

ion

• in config/initializer/mime_types.rb

Mime::Type.register "application/pdf", :pdf

Page 50: Action Controller Overview, Season 2

Parameter Filtering

config.filter_parameters << :password

• in config/application.rb

Page 51: Action Controller Overview, Season 2

Rescueclass ApplicationController < ActionController::Base  rescue_from User::NotAuthorized, :with => :user_not_authorized   private   def user_not_authorized    flash[:error] = "You don't have access to this section."    redirect_to :back  endend class ClientsController < ApplicationController  # Check that the user has the right authorization to access clients.  before_filter :check_authorization   # Note how the actions don't have to worry about all the auth stuff.  def edit    @client = Client.find(params[:id])  end   private   # If the user is not authorized, just throw the exception.  def check_authorization    raise User::NotAuthorized unless current_user.admin?  endend

Page 52: Action Controller Overview, Season 2

Force HTTPS protocol

class DinnerController  force_sslend

class DinnerController  force_ssl :only => :cheeseburger  # or  force_ssl :except => :cheeseburgerend

# Force all access to the app over SSL, use Strict-Transport-Security, and use secure cookies. config.force_ssl = true

Page 53: Action Controller Overview, Season 2

감사합니다.����������� ������������������