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

Ee9f9502f703ce754aa7feda9eefc579?s=128

Greg Malcolm

October 21, 2013
Tweet

Transcript

  1. New stuff in Rails 4

  2. or

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

  4. What’s  changed?

  5. Moved to Gem-space • Mass assignment • ActiveRecord::SessionStore • Action

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

    Caching, Page Caching, Cashew Cashing • Observers • ActiveResource • Sprockets
  7. 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:
  8. ActiveModel::Model class Tardis! include ActiveModel::Model! ! attr_accessor :doctor, ! :companion,

    ! :theme! ! validates :doctor, presence: true! validates :companion, length: { maximum: 20 }! end
  9. Finders ‘all’ is scopey now 2.0.0p0 :037 > Wizard.all.last!

  10. 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! => #<Wizard id: 7, name: "Bellatrix", alignment: "evil", spells: ["Avada Kedavra", "Accio"], bag_of_holding: nil, created_at: "2013-07-25 04:10:36", updated_at: "2013-07-25 04:10:36">
  11. 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:
  12. Form Helpers • collection_check_box • collection_radio_buttons Collections:

  13. Form Helpers • number_field • date_field • week_field • month_field

    • color_field • highlight HTML5:
  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
  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
  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
  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
  18. 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
  19. Russian Doll Caching

  20. Postgres Native Support • UUID • Network Address Types (IP4/IP6,

    MAC) • JSON • String Arrays • HStore
  21. Postgres class SetupHstore < ActiveRecord::Migration def self.up execute "create extension

    hstore" end ! def self.down execute "drop extension hstore" end end
  22. 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
  23. 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
  24. 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' }
  25. Postgres class Wizard < ActiveRecord::Base store_accessor :bag_of_holding, :wand store_accessor :bag_of_holding,

    :toothbrush store_accessor :bag_of_holding, :cupboard end
  26. 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%'")
  27. Turbolinks

  28. ActiveRecord::Live

  29. 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

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