Slide 1

Slide 1 text

New stuff in Rails 4

Slide 2

Slide 2 text

or

Slide 3

Slide 3 text

What to do you want to do Rails 4?

Slide 4

Slide 4 text

What’s  changed?

Slide 5

Slide 5 text

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

Slide 6

Slide 6 text

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

Slide 7

Slide 7 text

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:

Slide 8

Slide 8 text

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

Slide 9

Slide 9 text

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

Slide 10

Slide 10 text

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! => #

Slide 11

Slide 11 text

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:

Slide 12

Slide 12 text

Form Helpers • collection_check_box • collection_radio_buttons Collections:

Slide 13

Slide 13 text

Form Helpers • number_field • date_field • week_field • month_field • color_field • highlight HTML5:

Slide 14

Slide 14 text

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

Slide 15

Slide 15 text

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

Slide 16

Slide 16 text

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

Slide 17

Slide 17 text

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

Slide 18

Slide 18 text

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

Slide 19

Slide 19 text

Russian Doll Caching

Slide 20

Slide 20 text

Postgres Native Support • UUID • Network Address Types (IP4/IP6, MAC) • JSON • String Arrays • HStore

Slide 21

Slide 21 text

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

Slide 22

Slide 22 text

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

Slide 23

Slide 23 text

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

Slide 24

Slide 24 text

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' }

Slide 25

Slide 25 text

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

Slide 26

Slide 26 text

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%'")

Slide 27

Slide 27 text

Turbolinks

Slide 28

Slide 28 text

ActiveRecord::Live

Slide 29

Slide 29 text

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

Slide 30

Slide 30 text

@gregmalcolm http://github.com/gregmalcolm