sexta-feira, 29 de novembro de 2013

Ruby on Rails-Layout and Rendering

Layout and Rendering

====
   Based on guides.rubyonrails.org

Creating response
     Communication between View and Controller
     3 Ways to create HTTP response
            Call "render" to create a full response to send back to the browser
            Call "redirect_to" to send an HTTP redirect status code to the browser
            Call "head" to create a response consisting solely of HTTP headers to send back to the browser

     Convention over configuration
            By default, controllers automatically render views  with names of the route.
            Ex:
                        In route.rb:
                                   resources :books
                        class BooksController < ApplicationController
                          def index
                            @books = Book.all
                          end
                        end
                        - Try to render  app/views/books/index.html.erb which is the same name as the methods(index)
     Using render
            It is possible to render text, JSON or XML.  Can specify content type or HTTP status of the rendered response.

            If use render_to_string, just returns a string instead to send to the response to browser.

            Rendering nothing
                        render nothing: true
     Rendering a action's view
            render "edit"
            #OR
            render :edit
     Render template
            render template: "books/edit"
            render template: "books/edit.html.erb"
     To render a specific file
            render file: "/u/apps/warehouse_app/current/app/views/products/show"
     Render inline
            render inline: "<% products.each do |p| %><%= p.name %>
<% end %>"
     Render text
            render text: "OK"
     Render JSON
            render json: @product
     Render XML
            render xml: @product
     Render JavaScript
            render js: "alert('Hello Rails');"
     Options
            :content_type
                        - text/html, application/json, application/xml
                        ex: render file: filename, content_type: "application/rss"
            :layout
                        render layout: "special_layout"
                        render layout: false
            :location
                        To set HTTP Location header
                        render xml: photo, location: photo_url(photo)
            :status
                        render status: 500
                        #OR
                        render status: :forbidden
     Fiding Layouts
            First Rails try to set the same layout as the Controller, if it doesn't find, look for the layouts/application.html.erb.
            It is possible to specify a layout.
            ex:
                        class ProductsController < ApplicationController
                          layout "inventory"
                          #...
                        end
            To assign a specific layout for the entire application, use layout in ApplicationController
            ex:
                        class ApplicationController < ActionController::Base
                          layout "main"
                          #...
                        end
     Specifying a layout in runtime
            class ProductsController < ApplicationController
              layout :products_layout
             
              def show
                @product = Product.find(params[:id])
              end
             
              private
                def products_layout
                  @current_user.special? ? "special" : "products"
                end
             
            end
            Or with inline method
            class ProductsController < ApplicationController
              layout Proc.new { |controller| controller.request.xhr? ? "popup" : "application" }
            end
     Conditionanl Layouts
            class ProductsController < ApplicationController
              layout "product", except: [:index, :rss]
            end
Using redirect_to
     Tells the browser to send a new request from a different URL.
     Ex:
            redirect_to photos_url  #Redirect to index of photos
     Send back to the previous page
            redirect_to :back
     Differences
            render action: "index"    # Doesn't run the target code
            redirect_to action: :index   #Browser redirect to the action
                        Drawback is that it sends a 302 redirect response to the browser
Head only response
     ex:
            head :bad_request
            head :created, location: photo_path(@photo)

Structuring Layout
     Asset tags : Asset tag helpers provide methods for generating HTML that link views to feeds, JavaScript, stylesheets, images, videos and audios. There are six asset tag helpers available in Rails:
            auto_discovery_link_tag
            javascript_include_tag
                        Rails looks for java scripts in the following directories:  app/assets, lib/assets or vendor/assets
                        If use:
                                   <%= javascript_include_tag "main", "columns" %>
                        Executes:
                                   
 <script src='/assets/javascript/main.js'></script>  
 <script src='/assets/javascript/columns.js'></script>  

            stylesheet_link_tag
                        Similar to JavaScript.
                        If use:
                                   <%= stylesheet_link_tag "main", "photos/columns" %>
                        Includes
                                   app/assets/stylesheets/main.css and app/assets/stylesheets/photos/columns.css
                        External:
                                   <%= stylesheet_link_tag "http://example.com/main.css" %>

            image_tag
                        Builds an HTML tag.  Loaded by public/images or app/assets/images
                        Ex:
                                   <%= image_tag "home.gif", alt: "Go Home",
                      id: "HomeImage",
                      class: "nav_bar" %>

            video_tag
                        Builds an HTML 5
                        Ex:
                                   <%= video_tag "movie.ogg" %>
                        Executes:
                                  
  <video src="/videos/movie.ogg" />  
                        Multiple videos
                                   <%= video_tag ["trailer.ogg", "movie.ogg"] %>
                                   Executes:
                                                
 <video><source src="trailer.ogg" /><source src="movie.ogg" /></video>  
                        options: poster, autoplay, loop, controls, autobuffer
            audio_tag
                         Builds an HTML 5
                         <%= audio_tag "music.mp3" %>
                         Options: autoplay, controls,     autobuffer

     yield
            Identify a section where the content of a view should be inserted
       <html>  
        <head>  
        </head>  
        <body>  
        <%= yield %>  
        </body>  
       </html>  

     content_for
            To render content into a named yield, you use the content_for method.
            Useful when the layout contains distinct regions such as sidebars and footers with their own blocks.

       <% content_for :head do %>  
        <title>A simple page</title>  
       <% end %>  
       <p>Hello, Rails!</p>  

     Partials
            Files in the format _xxxx.html.erb that is inserted in the view.
            ex:
                        <%= render "shared/menu" %>
            Inset the file
                        app/views/shared/_menu.html.erb.
            Partial can have different layout
                        <%= render partial: "link_area", layout: "graybar" %>
            Passing local variables
                        EX:
                   <h1>New zone</h1>  
                   <%= error_messages_for :zone %>  
                   <%= render partial: "form", locals: {zone: @zone} %>  
             the _form.html.erb  
                   <%= form_for(zone) do |f| %>  
                    <p>  
                     <b>Zone name</b><br />  
                     <%= f.text_field :name %>  
                    </p>  
                    <p>  
                     <%= f.submit %>  
                    </p>  
                   <% end %>  

            Passing variables
                        <%= render partial: "customer", object: @new_customer %>
            Rending the same name as the object
                        <%= render @customer %>
                        Assumes that _custumer exists.           
            Colections
                        Will call the parcial as many times as the collection size rendering every elements of the collection.
                        <%= render partial: "product", collection: @products %>
                        and _product.html.erb
                                   Product Name: <%= product.name %>
            Array
                        Render each element of array
                        <%= render [customer1, employee1, customer2, employee2] %>
                        should have
                                   customers/_customer.html.erb
                                               Customer: <%= customer.name %>
                                   employees/_employee.html.erb
                                               Employee: <%= employee.name %>
            Spacer template
                        Render the spacer_template without any paremeter between each call to partials in collection.
                        <%= render partial: @products, spacer_template: "product_ruler" %>


quinta-feira, 28 de novembro de 2013

Ruby on Rails - Active Record Callbacks

Active Record Callbacks
====
   Based on guides.rubyonrails.org

     Callbacks are methods that is called in certain moment in a life-cicle of a object.  Callbacks are triggered by a specific operation over the Active Record Object.
     Ways of calling a callback
            - Creating a methods.  It can be set to run only in some lifecicle events
                        class User < ActiveRecord::Base
                          before_validation :normalize_name, on: :create
                         
                          # :on takes an array as well
                          after_validation :set_location, on: [ :create, :update ]
                         
                          protected
                          def normalize_name
                            self.name = self.name.downcase.titleize
                          end
                         
                          def set_location
                            self.location = LocationService.query(self)
                          end
                        end
            - Creating a block
                        class User < ActiveRecord::Base
                          validates :login, :email, presence: true
                         
                          before_validation :ensure_login_has_a_value
                         
                          protected
                          def ensure_login_has_a_value
                            if login.nil?
                              self.login = email unless email.blank?
                            end
                          end
                        end
     Running Callbacks
            Callbacks are triggered by using the following methods.                      
            create
            create!
            decrement!
            destroy
            destroy!
            destroy_all
            increment!
            save
            save!
            save(validate: false)
            toggle!
            update_attribute
            update
            update!
            valid?

            Calbacks for Creating an Object
                        before_validation
                        after_validation
                        before_save
                        around_save
                        before_create
                        around_create
                        after_create
                        after_save
            Calbacks for Updating an Object
                        before_validation
                        after_validation
                        before_save
                        around_save
                        before_update
                        around_update
                        after_update
                        after_save
            Calbacks for Destroying an Object
                        before_destroy
                        around_destroy
                        after_destroy
            Others callbacks
                        after_initialize
                                   Run then the Object is instantiated with new or loaded from DB.
                        after_find
                                   Run then the Object is loaded from DB.
                                   after_find is triggered by using the following finder methods:
                                               all
                                               first
                                               find
                                               find_by
                                               find_by_*
                                               find_by_*!
                                               find_by_sql
                                               last
     Halting Execution
            If an exception is thrown, the operation is halted or Rolledback
     Conditional Callbacks
            :if or :unles
            with a simbol
                        class Order < ActiveRecord::Base
                          before_save :normalize_card_number, if: :paid_with_card?
                        end
            Using String
                        Used in a short condition
                        class Order < ActiveRecord::Base
                          before_save :normalize_card_number, if: "paid_with_card?"
                        end
            With a Proc
                        Used in a short validation method
                        class Order < ActiveRecord::Base
                          before_save :normalize_card_number,
                            if: Proc.new { |order| order.paid_with_card? }
                        end
     Multiple Callbacks
            class Comment < ActiveRecord::Base
              after_create :send_email_to_author, if: :author_wants_emails?,
                unless: Proc.new { |comment| comment.post.ignore_comments? }
            end
     Callbacks Classes

     Transactionnal Callbacks
            after_commit and after_rollback.  Similar to after_save, but only execute after the changes  are commited or rolledback.  Usefull when system interacted with external applications.

            It is called insede a transaction block.  If a exception is thrown the callback is ignored, because they are called only after the operation on DB is finished.