Upgrade to Pro — share decks privately, control downloads, hide ads and more …

New Stuff in Rails 4

New Stuff in Rails 4

Sandbox Rails 4 demo project I've used for this presentation is here:
https://github.com/gregmalcolm/rails4demo

Greg Malcolm

October 21, 2013
Tweet

More Decks by Greg Malcolm

Other Decks in Programming

Transcript

  1. New stuff in Rails 4

    View full-size slide

  2. What to do you want to do Rails 4?

    View full-size slide

  3. What’s
    changed?

    View full-size slide

  4. Moved to Gem-space
    • Mass assignment
    • ActiveRecord::SessionStore
    • Action Caching, Page Caching, Cashew
    Cashing
    • Observers
    • ActiveResource
    • Sprockets

    View full-size slide

  5. Moved to Gem-space
    • Mass assignment
    • ActiveRecord::SessionStore
    • Action Caching, Page Caching, Cashew
    Cashing
    • Observers
    • ActiveResource
    • Sprockets

    View full-size slide

  6. ActiveModel
    class Tardis!
    include ActiveModel::Validations!
    include ActiveModel::Conversion!
    extend ActiveModel::Naming!
    !
    attr_accessor :doctor, !
    :companion, !
    :theme!
    !
    def initialize(attributes = {})!
    attributes.each do |k, v|!
    send(“#{k}=”, v)!
    end!
    end!
    end
    Rails 3:

    View full-size slide

  7. ActiveModel::Model
    class Tardis!
    include ActiveModel::Model!
    !
    attr_accessor :doctor, !
    :companion, !
    :theme!
    !
    validates :doctor, presence: true!
    validates :companion, length: { maximum: 20 }!
    end

    View full-size slide

  8. Finders
    ‘all’ is scopey now
    2.0.0p0 :037 > Wizard.all.last!

    View full-size slide

  9. Finders
    ‘all’ is scopey now
    2.0.0p0 :037 > Wizard.all.last!
    Wizard Load (0.8ms) SELECT "wizards".* FROM "wizards" ORDER BY "wizards"."id" DESC LIMIT 1!
    => #bag_of_holding: nil, created_at: "2013-07-25 04:10:36", updated_at: "2013-07-25 04:10:36">

    View full-size slide

  10. Finders
    • find_all_by_name(‘Gandalf’)

    • find_last_by_name(‘Rincewind’)

    • find_or_create_by_name(‘Hermione’)

    • find_or_create_by_name!(‘Merlin’)

    • find_or_initialize_by_name(‘Harry Dresden’)

    • scoped_by_name(‘Allanon’)
    Deprecated magic finders:

    View full-size slide

  11. Form Helpers
    • collection_check_box

    • collection_radio_buttons
    Collections:

    View full-size slide

  12. Form Helpers
    • number_field

    • date_field

    • week_field

    • month_field

    • color_field

    • highlight
    HTML5:

    View full-size slide

  13. class WizardsController < ApplicationController!
    before_action :set_wizard, only: [:show, :edit, :update, :destroy]!
    !
    ...!
    !
    # PATCH/PUT /wizards/1!
    # PATCH/PUT /wizards/1.json!
    def update!
    respond_to do |format|!
    if @wizard.update(wizard_params)!
    format.html { redirect_to @wizard, notice: 'Wizard was successfully
    updated.' }!
    format.json { head :no_content }!
    else!
    format.html { render action: 'edit' }!
    format.json { render json: @wizard.errors, status: :unprocessable_entity }!
    end!
    end!
    end!
    !
    ...!
    !
    private!
    # Use callbacks to share common setup or constraints between actions.!
    def set_wizard!
    @wizard = Wizard.find(params[:id])!
    end!
    !
    # Never trust parameters from the scary internet, only allow the white list
    through.!
    def wizard_params!
    params.require(:wizard).permit(:name, :alignment, :spells, :bag_of_holding)!
    end!
    end

    View full-size slide

  14. class WizardsController < ApplicationController!
    before_action :set_wizard, only: [:show, :edit, :update, :destroy]!
    !
    ...!
    !
    # PATCH/PUT /wizards/1!
    # PATCH/PUT /wizards/1.json!
    def update!
    respond_to do |format|!
    if @wizard.update(wizard_params)!
    format.html { redirect_to @wizard, notice: 'Wizard was successfully
    updated.' }!
    format.json { head :no_content }!
    else!
    format.html { render action: 'edit' }!
    format.json { render json: @wizard.errors, status: :unprocessable_entity }!
    end!
    end!
    end!
    !
    ...!
    !
    private!
    # Use callbacks to share common setup or constraints between actions.!
    def set_wizard!
    @wizard = Wizard.find(params[:id])!
    end!
    !
    # Never trust parameters from the scary internet, only allow the white list
    through.!
    def wizard_params!
    params.require(:wizard).permit(:name, :alignment, :spells, :bag_of_holding)!
    end!
    end

    View full-size slide

  15. class WizardsController < ApplicationController!
    before_action :set_wizard, only: [:show, :edit, :update, :destroy]!
    !
    ...!
    !
    # PATCH/PUT /wizards/1!
    # PATCH/PUT /wizards/1.json!
    def update!
    respond_to do |format|!
    if @wizard.update(wizard_params)!
    format.html { redirect_to @wizard, notice: 'Wizard was successfully
    updated.' }!
    format.json { head :no_content }!
    else!
    format.html { render action: 'edit' }!
    format.json { render json: @wizard.errors, status: :unprocessable_entity }!
    end!
    end!
    end!
    !
    ...!
    !
    private!
    # Use callbacks to share common setup or constraints between actions.!
    def set_wizard!
    @wizard = Wizard.find(params[:id])!
    end!
    !
    # Never trust parameters from the scary internet, only allow the white list
    through.!
    def wizard_params!
    params.require(:wizard).permit(:name, :alignment, :spells, :bag_of_holding)!
    end!
    end

    View full-size slide

  16. class WizardsController < ApplicationController!
    before_action :set_wizard, only: [:show, :edit, :update, :destroy]!
    !
    ...!
    !
    # PATCH/PUT /wizards/1!
    # PATCH/PUT /wizards/1.json!
    def update!
    respond_to do |format|!
    if @wizard.update(wizard_params)!
    format.html { redirect_to @wizard, notice: 'Wizard was successfully
    updated.' }!
    format.json { head :no_content }!
    else!
    format.html { render action: 'edit' }!
    format.json { render json: @wizard.errors, status: :unprocessable_entity }!
    end!
    end!
    end!
    !
    ...!
    !
    private!
    # Use callbacks to share common setup or constraints between actions.!
    def set_wizard!
    @wizard = Wizard.find(params[:id])!
    end!
    !
    # Never trust parameters from the scary internet, only allow the white list
    through.!
    def wizard_params!
    params.require(:wizard).permit(:name, :alignment, :spells, :bag_of_holding)!
    end!
    end

    View full-size slide

  17. class WizardsController < ApplicationController!
    before_action :set_wizard, only: [:show, :edit, :update, :destroy]!
    !
    ...!
    !
    # PATCH/PUT /wizards/1!
    # PATCH/PUT /wizards/1.json!
    def update!
    respond_to do |format|!
    if @wizard.update(wizard_params)!
    format.html { redirect_to @wizard, notice: 'Wizard was successfully
    updated.' }!
    format.json { head :no_content }!
    else!
    format.html { render action: 'edit' }!
    format.json { render json: @wizard.errors, status: :unprocessable_entity }!
    end!
    end!
    end!
    !
    ...!
    !
    private!
    # Use callbacks to share common setup or constraints between actions.!
    def set_wizard!
    @wizard = Wizard.find(params[:id])!
    end!
    !
    # Never trust parameters from the scary internet, only allow the white list
    through.!
    def wizard_params!
    params.require(:wizard).permit(:name, :alignment, :spells, :bag_of_holding)!
    end!
    end

    View full-size slide

  18. Russian Doll Caching

    View full-size slide

  19. Postgres Native
    Support
    • UUID

    • Network Address Types (IP4/IP6, MAC)

    • JSON

    • String Arrays

    • HStore

    View full-size slide

  20. Postgres
    class SetupHstore < ActiveRecord::Migration
    def self.up
    execute "create extension hstore"
    end
    !
    def self.down
    execute "drop extension hstore"
    end
    end

    View full-size slide

  21. Postgres
    class SetupHstore < ActiveRecord::Migration
    def self.up
    #execute "create extension hstore"
    system("psql template1 -c 'create extension hstore;'")
    end
    !
    def self.down
    #execute "drop extension hstore"
    system("psql template1 -c 'drop extension hstore;'")
    end
    end

    View full-size slide

  22. Postgres
    class CreateWizards < ActiveRecord::Migration
    def change
    create_table :wizards do |t|
    t.string :name
    t.string :alignment
    t.string :spells, array:true
    t.hstore :bag_of_holding
    !
    t.timestamps
    end
    end
    end

    View full-size slide

  23. Postgres
    Wizard.create name: 'Bellatrix',
    alignment: 'evil',
    spells: ['Avada Kedavra', 'Accio'],
    bag_of_holding: { wand: 'goose bone' }
    !
    Wizard.create name: 'Evil Willow',
    alignment: 'evil',
    spells: ['Sphere of Infinite Agonies',
    'Living Flame', 'Vine Bondage'],
    bag_of_holding: { wand: 'unicorn tears',
    toothbrush: 'evil' }

    View full-size slide

  24. Postgres
    class Wizard < ActiveRecord::Base
    store_accessor :bag_of_holding, :wand
    store_accessor :bag_of_holding, :toothbrush
    store_accessor :bag_of_holding, :cupboard
    end

    View full-size slide

  25. Postgres HStore
    Queries
    Who has a wand?
    Wizard.where("bag_of_holding ? 'wand'")

    Who has a specific wand?
    Wizard.where("bag_of_holding -> 'wand' like 't%'")

    View full-size slide

  26. ActiveRecord::Live

    View full-size slide

  27. Sourcery
    http://weblog.rubyonrails.org/2013/6/25/Rails-4-0-final/

    http://railscasts.com/

    http://blog.remarkablelabs.com/2012/11/rails-4-countdown-to-2013

    http://tenderlovemaking.com/2012/07/30/is-it-live.html

    View full-size slide

  28. @gregmalcolm http://github.com/gregmalcolm

    View full-size slide