23 May 2013

referring to Slide Presentation (Slide Numbers) see PDF - useful-rails-concepts-slides.pdf

Rails API - Slide 3

Rails API


For new apps - Install the gem if you haven’t already:

gem install rails-api

Then generate a new Rails::API app:

rails-api new my_api

AMS - Active Model Serializers


The easiest way to create a new serializer is to generate a new resource, which will generate a serializer at the same time:

rails g resource post title:string body:string

This will generate a serializer in app/serializers/post_serializer.rb for your new model. You can also generate a serializer for an existing model with the serializer generator:

rails g serializer post

Example of created serializer:

class PostSerializer < ActiveModel::Serializer
  attributes :id, :title, :string

Navigating to the URL localhost/posts would then render a JSON string response. The rails g resource command would already have created an entry in routes.rb to include the posts resource, as such allowing index access, rendering posts.json.

API access, Tokens

to wrap an API, include in routes.rb, for example using the products resource:

namespace :api do
  namespace :v1 do
    resources :products

then create a controller in api/v1/products_controller, where the before_filter :restrict_access calls the token authentication, which is an API table containing a row with the SHA1 hash. If you navigate to e.g. localhost/api/v1/products.json?access_token=1234d607b688b43841f1c6ccfe57a69e

module Api
  module V1
    class ProductsController < ApplicationController
      before_filter :restrict_access
      skip_before_filter :require_login, :only => [:index, :show]
      respond_to :json
      caches_action :index, :show
      def index
        @products = Product.all

        respond_to do |format|
          format.json { render json: @products, :only => [:id, :level, :condo_no, :sales_no, :sqr_ft, :schedule_b, :seating, :restaurant, :hair, :food, :herbs_dsf, :pets, :extended_hours, :standard_hours, :category_txt, :availability, :price, :notes] }
        ActiveRecord::Base.include_root_in_json = false
      def show
        @product = Product.find(params[:id])

        respond_to do |format|

          format.json { render json: @product, :only => [:id, :level, :condo_no, :sales_no, :sqr_ft, :schedule_b, :seating, :restaurant, :hair, :food, :herbs_dsf, :pets, :extended_hours, :standard_hours, :category_txt, :availability, :price, :notes] }

        ActiveRecord::Base.include_root_in_json = false

      def restrict_access
        api_key = ApiKey.find_by_access_token(params[:access_token])
        head :unauthorized unless api_key

      def restrict_access2
        authenticate_or_request_with_http_token do |token, options|
          ApiKey.exists?(access_token: token)

For token based access - Railscasts episode #352 is helpful http://railscasts.com/episodes/352-securing-an-api?view=asciicast

Security, Strong Params, whitelisting

By default Rails now creates whitelisted accessors in models to control access to attributes. Previously, a security hole was discovered that allowed a malicious web app to send updates to attributes (Mass Assignment) through the helper methods update_attributes and new.

Example of previously unsafe update_attributes method in controller method update:

def update
  @order = Order.find(params[:id])

  respond_to do |format|
    if @order.update_attributes(params[:order])
      format.html { redirect_to @order, notice: 'Order was successfully updated.' }
      format.json { head :no_content }
      format.html { render action: "edit" }
      format.json { render json: @order.errors, status: :unprocessable_entity }

See also Rails Guides Security Article on Mass Assignment - http://guides.rubyonrails.org/security.html#mass-assignment

Without any precautions Model.new(params[:model]) would allow attackers to set any database 
column’s value.

The mass-assignment feature may become a problem, as it allows an attacker to set any model’s attributes by manipulating the hash passed to a model’s new() method:

def signup
  params[:user] # => {:name => “ow3ned”, :admin => true}
  @user = User.new(params[:user])

Mass-assignment allows passing in a hash to the new method, or assign_attributes= to set the model’s attributes to the values in the hash. It is often used with the parameters (params) hash available in controller, which may be used with malicious intent. Changing URL example:

Simple GET request http://www.example.com/user/signup?user[name]=ow3ned&user[admin]=1

It’s worth reading the Rails security Guide - http://guides.rubyonrails.org/security.html

Example of whitelisting params in model - is generated automatically upon resource creation (e.g. rails g resource ProductDetail ProductID:string ProductName:string :ProductUPCCode:string) or scaffold creation (replace resource in generate command with scaffold if one needs HTML views):

class ProductDetail < ActiveRecord::Base
  attr_accessible :ProductId, :ProductName, :ProductUPCCode

Routes - Slide 12


RESTful routes creation with resources :products vs. using match (catch-all for get and post), get, post.

Catch params (params[:id]) with match "store/categories/(:id)" => "store#categories".

Route nesting

Nest routes with e.g.

resources :blogs do
  resources :posts

resources :posts do
  resources :comments

There is an article by Jamis Buck (37 Signals) about avoiding deeply nested routes - see http://weblog.jamisbuck.org/2007/2/5/nesting-resources. See also Rails Guides routing - http://guides.rubyonrails.org/routing.html

Specifically http://guides.rubyonrails.org/routing.html#crud-verbs-and-actions e.g. resources :photos command creates 7 different routes on the Photos controller:

HTTP Verb Path action used for
GET /photos index display a list of all photos
GET /photos/new new return an HTML form for creating a new photo
POST /photos create create a new photo
GET /photos/:id show display a specific photo
GET /photos/:id/edit edit return an HTML form for editing a photo
PUT /photos/:id update update a specific photo
DELETE /photos/:id destroy delete a specific photo

rake routes

rake routes command shows all available routes and their named paths, which can be used to e.g. generate link helpers. edit_post_comment refers and generates the route GET /posts/:post_id/comments/:id/edit(.:format):

          post_comments GET    /posts/:post_id/comments(.:format)          {:action=>"index", :controller=>"comments"}
                        POST   /posts/:post_id/comments(.:format)          {:action=>"create", :controller=>"comments"}
       new_post_comment GET    /posts/:post_id/comments/new(.:format)      {:action=>"new", :controller=>"comments"}
      edit_post_comment GET    /posts/:post_id/comments/:id/edit(.:format) {:action=>"edit", :controller=>"comments"}
           post_comment GET    /posts/:post_id/comments/:id(.:format)      {:action=>"show", :controller=>"comments"}
                        PUT    /posts/:post_id/comments/:id(.:format)      {:action=>"update", :controller=>"comments"}
                        DELETE /posts/:post_id/comments/:id(.:format)      {:action=>"destroy", :controller=>"comments"}
                  posts GET    /posts(.:format)                            {:action=>"index", :controller=>"posts"}
                        POST   /posts(.:format)                            {:action=>"create", :controller=>"posts"}
               new_post GET    /posts/new(.:format)                        {:action=>"new", :controller=>"posts"}
              edit_post GET    /posts/:id/edit(.:format)                   {:action=>"edit", :controller=>"posts"}
                   post GET    /posts/:id(.:format)                        {:action=>"show", :controller=>"posts"}
                        PUT    /posts/:id(.:format)                        {:action=>"update", :controller=>"posts"}
                        DELETE /posts/:id(.:format)                        {:action=>"destroy", :controller=>"posts"}
               comments GET    /comments(.:format)                         {:action=>"index", :controller=>"comments"}
                        POST   /comments(.:format)                         {:action=>"create", :controller=>"comments"}
            new_comment GET    /comments/new(.:format)                     {:action=>"new", :controller=>"comments"}
           edit_comment GET    /comments/:id/edit(.:format)                {:action=>"edit", :controller=>"comments"}
                comment GET    /comments/:id(.:format)                     {:action=>"show", :controller=>"comments"}
                        PUT    /comments/:id(.:format)                     {:action=>"update", :controller=>"comments"}
                        DELETE /comments/:id(.:format)                     {:action=>"destroy", :controller=>"comments"}

SPA Single Page Apps - Slide 4

Example of Standard jQuery/ Ajax use in Rails

Good jQuery reference for Ajax etc. - http://jqfundamentals.com/

Ajax GET Request

e.g. a music track selector widget:

selector widget

Html page includes two selectors and a link (action), where jQuery references the two id fields categories and sort in the event of click, binding events to these id’s with jQuery’s live capture (one could just use the click event, but then it would not register changes from both selectors):

<script type="text/javascript">

    jQuery(function($) {

        // prod_select ajax get function
        $('#get_category').live('click',function () {
            $.get("/home/articles", {cat: $('#categories').val(), sort: $('#sort').val()}, null, 'script');
            return false;


Then in the home_controller articles method we refer to an articles.js articles.js.erb file, which has the same name as the articles method (we could call it something else, but then would have to specify name in the respond_to block):

def articles

  category_selected = params[:cat]
  sort_by = params[:sort]

  #do some magic with the params...

  respond_to do |format|

articles.js.erb file, inserting a count (through erb) and a partial into the page, updating the displayed list of articles (songs):

/* comment */
$("#articles_count").html("<%= pluralize(@articles.count, 'Article') %>");

/* comment */
$("#articles").html("<%= escape_javascript(render('home/article')) %>");

The render('home/article') refers to a partial _article.html.erb that Rails inserts into the page:

  <% @articles.each do |article| -%>
     <td><a href = "/articles/<%= article.id %>"><img src="/assets/note.png"/></a></td>
     <td><h2><a href="/articles/<%= article.id %>"><strong><%= article.name %> - <%= h truncate(article.description_en, :length => 80) %></strong></a></h2>

      <p class="summary"><%= article.description_en %></p>

  <% end -%>

Ajax POST Request

Same workflow as GET Request (see above) but jQuery Ajax helper would be using $.post instead of $.get.

Another way to create Ajax POST requests automatically is to use the :remote => true helper in Rails forms:

<% form_tag products_path, :remote => true do %>
    <%= text_field_tag :search, params[:search] %>
    <%= submit_tag "Search", :name => nil %>
<% end %>

Rails Guides simple Ajax example http://edgeguides.rubyonrails.org/working_with_javascript_in_rails.html#a-simple-example

There are also various Railscasts.com articles on Ajax/ jQuery that might be a useful - see http://railscasts.com/episodes/240-search-sort-paginate-with-ajax?view=asciicast


Refer to Ember.js Guides - see intro video http://emberjs.com/guides/, Github project with code https://github.com/tildeio/bloggr-client

Also Peepcode Episode on Ember - https://peepcode.com/products/emberjs, an inofficial Github project with code (might work, it’s a copy of Peepcode’s commercial offering) https://github.com/jordelver/peepcode-ember-js

Devmynd article on Ember.js - http://www.devmynd.com/blog/2013-3-rails-ember-js

Also - http://www.embercasts.com/ and http://ember101.com/

Ember.js Routing magic - see http://emberjs.com/guides/routing/defining-your-routes/

App.Router.map(function() {
  this.resource('posts', function() {

creates the following routes:

URL Route Name Controller Route Template
/ index IndexController IndexRoute index
N/A posts1 PostsController PostsRoute posts
/posts posts.index PostsController
/posts/new posts.new PostsController


See - Angularjs.org and Angular video intros http://www.egghead.io/

Rails Console - Slide 8


Rails console in production - rails c RAILS_ENV=production (in dev mode you can leave out the RAILS_ENV part).


Enhanced Rails console with data introspection and breakpoints etc. - http://railscasts.com/episodes/280-pry-with-rails?view=asciicast

also https://github.com/pry/pry

Admins - Rails Admin, Active Admin, Netzke - Slide 19

Rais Admin

Rails admin - https://github.com/sferik/rails_admin and link to demo http://rails-admin-tb.herokuapp.com/

Active Admin

Active Admin - http://activeadmin.info/, Github https://github.com/gregbell/active_admin


Creates Grids based on ExtJS - http://netzke.org/

Authentication, Authorization - Slide 5

Autentication - Sorcery, Devise

Authentication with Sorcery - https://github.com/NoamB/sorcery, see Wiki install and configuration https://github.com/NoamB/sorcery/wiki

Authentication with Devise - https://github.com/plataformatec/devise, see Wiki https://github.com/plataformatec/devise/wiki

Authorization - CanCan Example

Authorization with CanCan - https://github.com/ryanb/cancan, CanCan Wiki https://github.com/ryanb/cancan/wiki

CanCan Ability model class example:

See also Railscasts episodes on CanCan - http://railscasts.com/episodes/192-authorization-with-cancan?view=asciicast

class Ability
  include CanCan::Ability
  include ApplicationHelper

  #def initialize(user)
    # Define abilities for the passed in user here. For example:
    #   user ||= User.new # guest user (not logged in)
    #   if user.admin?
    #     can :manage, :all
    #   else
    #     can :read, :all
    #   end
    # The first argument to `can` is the action you are giving the user 
    # permission to do.
    # If you pass :manage it will apply to every action. Other common actions
    # here are :read, :create, :update and :destroy.
    # The second argument is the resource the user can perform the action on. 
    # If you pass :all it will apply to every resource. Otherwise pass a Ruby
    # class of the resource.
    # The third argument is an optional hash of conditions to further filter the
    # objects.
    # For example, here the user can only update published articles.
    #   can :update, Article, :published => true
    # See the wiki for details:
    # https://github.com/ryanb/cancan/wiki/Defining-Abilities

  def initialize(user)
    @user = user || User.new # for guest
    @user.roles.each { |role| send(role.name.to_sym) }
    @organizations = Organization.all

    if @user.roles.size == 0
      can :read, :all #for guest without roles

  def account

    #can [:manage], [Organization, User, CustomerRecord, AdminRecord, Vendor, Product, PriceList, BankRecord, CreditCardRecord, Category, Page, Location, Order, LineItem, OrderTransaction, Access]
    can :manage, :all

  def exceptions_to_rules
    cannot :destroy, Organization

  def management
    can [:read, :create, :update], [Organization, User, CustomerRecord, AdminRecord, Vendor, Product, PriceList, BankRecord, CreditCardRecord, Location, Order, OrderTransaction, Access]
    can [:read], [Category, LineItem]

  def management_division
    can [:read, :create, :update], [Organization, User, CustomerRecord, AdminRecord, Vendor, Product, PriceList, BankRecord, CreditCardRecord, Category, Location, Order, LineItem, OrderTransaction, Access]
    can [:read], [Category, LineItem]

  def staff
    can [:read, :create, :update], [User, CustomerRecord]
    can [:read], [Organization, Category, PriceList, AdminRecord, Vendor]


In user.rb model you create the helper method role?, which helps pass in the associated roles table by collecting the role names (many-to-one relationship between Role and User), which ability.rb then refers to in the initialize method dynamically for each user (using send() to turn role name strings into methods, e.g. def management def staff etc.).

 def role?(role)
    roles.map {|s| s.name}.include? role.to_s

Finally (taken from Railscast Article), if you refer (with logged in user) with the can? view helper method to the user’s abilities, it filters for allowed operations (which can be any operation which has been defined in CanCan’s ability class, not only CRUD operations - create, read, update, delete). CanCan automatically attaches abilities to the controllers. Example of view helper using CanCan:

  <% if can? :update, @article %>
    <%= link_to "Edit", edit_article_path(@article) %> |
  <% end %>
  <% if can? :destroy, @article %>
    <%= link_to "Destroy", @article, :method => :delete, :confirm => "Are you sure?" %> |
  <% end %>
  <%= link_to "Back to Articles", articles_path %>

Active Record Finder - Slide 7


See Rails Guides article - http://guides.rubyonrails.org/active_record_querying.html

Search scopes

Search scopes (Devmynd Article) - http://www.devmynd.com/blog/2013-3-effective-rails-part-2-hiding-activerecord

Hiding Actice Record behind search scopes:

# app/models/order.rb
class Order < ActiveRecord::Base

  def self.recent_open_orders_for_customer(customer, page, size=20)
    open.for_customer(customer).by_recency.paged(page, size).to_a

  scope :open, ->{ where(status: "open") }
  scope :for_customer, ->(customer) { where(customer: customer) }
  scope :by_recency, ->{ order("created_at DESC") }
  scope :paged, ->(page, size=20) { offset(size).limit(size) }


# app/controllers/orders_controller.rb
class OrdersController < ApplicationController

  def index
    @orders = Order.recent_open_orders_for_customer(
      current_customer, params[:page], params[:page_size])


Active Record Associations - Slide 10

has_many, belongs_to, has_many :through

acts_as_tree - https://github.com/amerine/acts_as_tree, a bit dated but still functional http://railscasts.com/episodes/162-tree-based-navigation?view=asciicast

awesome_nested_set (nested set) - https://github.com/collectiveidea/awesome_nested_set/

polymorphic associations

many_to_many with behaviour

STI - single table inheritance

see ‘Rails Recipes’ book, or ‘Rails Cookbook’ (contain many of these examples)

Storing Flexible Data, NoSQL - Slide 11

Postgres Hstore - see DevMynd article http://www.devmynd.com/blog/2013-3-single-table-inheritance-hstore-lovely-combination

Active Record Postgres hstore gem - https://github.com/engageis/activerecord-postgres-hstore

hstore gem is built into Rails 4

Serializing flexible attributes into Rails, built into Rails 3.

Referring to PDF doc ‘Postgres Experts - Simplifying DB Design’ - simple_db.pdf

Concepts from PDF:

EAV tables (‘Eavil table’) data blob (‘e-blob’)

MongoDB - no transactions

Faking out transactions in MongoDB - http://blog.mongodb.org/post/7494240825/master-detail-transactions-in-mongodb

Postgresql 9.3 - FDW (integrating Redis, MongoDB)

PostgreSQL 9.3 beta: Federated databases and more - http://lwn.net/Articles/550418/

See ‘Linking PostgreSQL to Redis’ in article.

PostGresql new features

links - https://postgres.heroku.com/blog/past/2012/3/14/introducing_keyvalue_data_storage_in_heroku_postgres/, Postgres the bits you haven’t found, Embracing the Web with JSON and V8, NoSQL in Postgres intro

Rails Asset Pipeline, Twitter Bootstrap Framework - Slide 17

Asset Pipeline

Rails Guides to Asset Pipeline - http://guides.rubyonrails.org/asset_pipeline.html

Integrating Bootstrap, Less, SASS

Twitter Bootstrap - http://twitter.github.io/bootstrap/

Less - http://lesscss.org/

SASS - http://sass-lang.com/

Handling Data, CSV, Excel, PDF generation - Slide 16

CSV Import

Note - db/seeds.rb is the preferred way to create db data e.g. rake db:seed (or rake db:seed RAILS_ENV=production), also http://edgeguides.rubyonrails.org/migrations.html#migrations-and-seed-data

CSV import - create a load_data.rake task in lib/tasks directory of Rails app. Example of complex load task (one could split these up into separate rake tasks) - execute task with rake db:load:load_data:

# Provide tasks to load and delete data.
require 'active_record'
require 'active_record/fixtures'

namespace :db do
  DATA_DIRECTORY = File.join(Rails.root, "lib", "tasks", "load_csv")
  namespace :load_data do 
    TABLES = %w(categories products)
    #MIN_USER_ID = 100    # Starting user id for the sample data
    desc "Load data"
    task :load => :environment do |t|
      require 'csv'
      CSV.foreach("lib/tasks/load_csv/categories.csv", :headers => true) do |row|
        Category.create(:name => row['name'], :description => row['description'], :created_at => Time.now, :updated_at => Time.now)
      puts "categories o.k."
      CSV.foreach("lib/tasks/load_csv/products.csv", :headers => true, :col_sep => ",") do |row|
        Product.create(:organization_id => '1', :vendor_id => '1', :category_id => '1', 
        :made_in_canada => false, :available => row['available'], :manufacturer_nr => row['manufacturer_nr'],
        :created_at => Time.now, :updated_at => Time.now)
      puts "products o.k."
    desc "Remove data" 
    task :delete => :environment do |t|
      TABLES.each do |t|
        klass = t.classify.constantize
        #id = klass == User ? "id" : "user_id"
        #klass.delete_all("#{id} >= #{MIN_USER_ID}")


It reads in various CSV files in the lib/tasks/load_csv directory, e.g. categories.csv:

garden,garden products
bath,bath products

PDF generation

Prawn - http://prawn.majesticseacreature.com/ and https://github.com/prawnpdf/prawn

Or PDFKit - https://github.com/pdfkit/pdfkit, also PDF toolkit (large collections of PDFs) - http://www.pdflabs.com/tools/pdftk-the-pdf-toolkit/

Simple example with Prawn:

require 'prawn'

Prawn::Document.generate('hello.pdf') do |pdf|
  pdf.text("Hello Prawn!")