Your SlideShare is downloading. ×
Saving this for later? Get the SlideShare app to save on your phone or tablet. Read anywhere, anytime – even offline.
Text the download link to your phone
Standard text messaging rates apply

Action Controller Overview, Season 2


Published on

Published in: Education
1 Like
  • Be the first to comment

No Downloads
Total Views
On Slideshare
From Embeds
Number of Embeds
Embeds 0
No embeds

Report content
Flagged as inappropriate Flag as inappropriate
Flag as inappropriate

Select your reason for flagging this presentation as inappropriate.

No notes for slide


  1. Ror lab. season 2 - the 15th round -Action Controller Overview February 2th, 2013 Hyoseong Choi
  2. A Controller• RESTful applications• like an orchestra conductor• as a middle man btw models and views
  3. REST URI with HTTP methods#index #new #edit GET /books HTTP/1.1 GET /books/new HTTP/1.1 GET /books/1/edit HTTP/1.1 Host: Host: Host: Accept: application/xml Accept: application/xml Accept: application/xml#show #create #update GET /books/1 HTTP/1.1 POST /books HTTP/1.1 PUT /books/1 HTTP/1.1 Host: Host: Host: Accept: application/xml Accept: application/xml Accept: application/xml #destroy DELETE /books/1 HTTP/1.1 Host: Accept: application/xml
  4. URI? http://domain_name/posts/114• Uniform Resource Identifier = URL + URN = Uniform Resource Locator + Uniform Resource Name
  5. Routing$ rake routes CONTROLLER=books books GET /books(.:format) books#index POST /books(.:format) books#create new_book GET /books/new(.:format) books#newedit_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 HTTP resource Controllers routes verbs URI Actions
  6. MVC
  7. MVC Controller View Model
  8. Methods & Actions• A “class” has methods• A controller < ApplicationController• public methods => “action” <= routing actions $ rake routes CONTROLLER=clients clients GET /clients(.:format) clients#index POST /clients(.:format) clients#create new_client GET /clients/new(.:format) clients#new edit_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
  9. Parameters• Two kinds of parameters - Query string - POST data• by params hash for both of these• “Routing” parameters
  10. Hash & Array Params for Query String GET /clients?ids[]=1&ids[]=2&ids[]=3 params[:ids] ? [ “1”, “2”, “3”]
  11. Hash & Array Params for POST data<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> { “name” => “Acme”, “phone” => “12345”,params[:client] ? “address” => { “postcode” => “12345”, “city” => “Carrot City” } }
  12. JSON/XML ParamsJSON parameter{ "company": { "name": "acme", "address": "123 Carrot Street" } } automatically converted to params hash by Railsparams[:company]{ :name => “acme”, “address” => “123 Carrot Street” }
  13. 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}   end end
  14. 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) %># =><%= url_for(:action => play, :anchor => player) %># => /messages/play/#player<%= url_for(:action => jump, :anchor => tax&ship) %># => /testing/jump/#tax&ship<%= url_for( %># 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("") %># =><%= url_for(:back) %># if request.env["HTTP_REFERER"] is set to ""# =><%= url_for(:back) %># if request.env["HTTP_REFERER"] is not set or is blank# => javascript:history.back()
  15. Session stateless ➤ stateful in controllersSession Repositories :• ActionDispatch::Session::CookieStore• ActionDispatch::Session::CacheStore• ActionDispatch::Session:: ActiveRecordStore• ActionDispatch::Session::MemCacheStore
  16. Session Accessing the Session lazily loadedclass 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] =      redirect_to root_url    end  endend
  17. Session Removing a Session Keyclass 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  endendcf. reset_session
  18. Session Flash a disposable session• special session : Hash• cleared with each request• only available in the next request• useful for storing error messages etc
  19. Session Flashredirect_to root_url, notice: "You have successfully logged out."redirect_to root_url, alert: "Youre stuck here!"redirect_to root_url, flash: { referral_code: 1234 }
  20. Session Flash<html>  <!-- <head/> -->  <body>    <% flash.each do |name, msg| -%>      <%= content_tag :div, msg, class: name %>    <% end -%>     <!-- more content -->  </body></html>
  21. Session Flash<% if flash[:just_signed_up] %>  <p class="welcome">Welcome to our site!</p><% end %>
  22. Session Flash flash.keepclass MainController < ApplicationController  # Lets 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
  23. Session Flash flash.nowclass ClientsController < ApplicationController  def create    @client =[:client])    if      # ...    else[:error] = "Could not save client"      render :action => "new"    end  endend
  24. Cookies• persisted across request and even sessions class CommentsController < ApplicationController   def new     # Auto-fill the commenters name if it has been stored in a cookie     @comment = => cookies[:commenter_name])   end     def create     @comment =[:comment])     if       flash[:notice] = "Thanks for your comment!"       if params[:remember_name]         # Remember the commenters name.         cookies[:commenter_name] =       else         # Delete cookie for the commenters name cookie, if any.         cookies.delete(:commenter_name)       end       redirect_to @comment.article     else       render :action => "new"     end   end end
  25. Cookies• to delete a cookie value cookies.delete(:key)
  26. xml & json dataclass 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
  27. Filters methods inherited before Action afterto halt action not to halt action around
  28. 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
  29. Filters• skip_before_filter class LoginsController < ApplicationController   skip_before_filter :require_login, :only => [:new, :create] end
  30. Filters• around_filter 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   end end
  31. Filters• Three Ways to use Filters - a private method - a block - a class
  32. 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?)   end end
  33. Filters• Using a Class in more complex cases class ApplicationController < ActionController::Base   before_filter LoginFilter end   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   end end
  34. CSRF• Site to site hacking• First step for this with non-GET request :create/update/destroy• RESTful default to protect CSRF• Nevertheless, non-GET request still vulnerable
  35. 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>
  36. CSRF• form_authenticity_token in custom Ajax calls
  37. Request & Response Objects• Two methods in every controller - `request` method => request object - `response` method => response object
  38. Request Objects
  39. Request Objects• Three hash parameters for request objects - path_parameters - query_parameters : query string - request_parameters : post data
  40. Response Objects• like in an `after` filter
  41. Response Objects response.headers["Content-Type"] = "application/pdf"
  42. HTTPAuthentications
  43. HTTP Authentications• Two types - Basic authentication : using base 64 encoding - Digest authentication : using MD5 encoding
  44. HTTP Authentications• Basic authentication class AdminController < ApplicationController   http_basic_authenticate_with :name => "humbaba", :password => "5baa61e4" end
  45. 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   end end Safari v 6.0.2 undefined method `unpack for nil:NilClass
  46. Streaming & File Downloads•send_data•send_file 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 => "#{}.pdf",               :type => "application/pdf", :disposition => "attachement"   end     private     def generate_pdf(client) do       text, :align => :center       text "Address: #{client.address}"       text "Email: #{}"     end.render   end end send_data
  47. Streaming & File Downloadsclass 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/#{}.pdf",              :filename => "#{}.pdf",              :type => "application/pdf")  endend send_file
  48. Streaming & File Downloadsin a RESTful application #153(revised) 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) do       text, :align => :center       text "Address: #{client.address}"       text "Email: #{}"     end.render   end end send_file
  49. Streaming & File Downloads • in config/initializer/mime_types.rbin a RESTful application Mime::Type.register "application/pdf", :pdf send_file
  50. Parameter Filtering• in config/application.rbconfig.filter_parameters << :password
  51. Rescueclass ApplicationController < ActionController::Base  rescue_from User::NotAuthorized, :with => :user_not_authorized   private   def user_not_authorized    flash[:error] = "You dont 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 dont 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
  52. Force HTTPS protocolclass DinnerController  force_sslendclass 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
  53. 감사합니다.