• Like

Action Controller Overview, Season 2

Uploaded on


More in: Education
  • Full Name Full Name Comment goes here.
    Are you sure you want to
    Your message goes here
    Be the first to comment
    Be the first to like this
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: rorlab.org Host: rorlab.org Host: rorlab.org 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: rorlab.org Host: rorlab.org Host: rorlab.org Accept: application/xml Accept: application/xml Accept: application/xml #destroy DELETE /books/1 HTTP/1.1 Host: rorlab.org 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) %># => 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()
  • 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] = 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.new(params[:client])    if @client.save      # ...    else      flash.now[: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 = 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 commenters name.         cookies[:commenter_name] = @comment.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 => "#{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   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/#{client.id}.pdf",              :filename => "#{client.name}.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)     Prawn::Document.new do       text client.name, :align => :center       text "Address: #{client.address}"       text "Email: #{client.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. 감사합니다.
  • 54.