D-Talk: What's awesome about Ruby 2.x and Rails 4

Preview:

DESCRIPTION

D-Talk by Jan Berdajs

Citation preview

RUBY 2.X

Thursday, October 10, 13

2012Thursday, October 10, 13

RUBY

+ berljivost+ površinska enostavnost+ polno objektni jezik+ funkcijsko programiranje+ metaprogramiranje+ ekosistem+ RubyGems

- metaprogramiranje- hitrost vs. Scala, Java, C- znanost (SciPy)

Thursday, October 10, 13

(0..10).each do |x| puts "The number is: #{x}"end

<?php for ($x=0; $x<=10; $x++){ echo "The number is: $x";}?>

for x in range(0, 11): print 'The number is: %d' % (x)

Ruby PHP Python

Thursday, October 10, 13

(0..10).each do |x| puts "The number is: #{x}"end

<?php for ($x=0; $x<=10; $x++){ echo "The number is: $x";}?>

for x in range(0, 11): print 'The number is: %d' % (x)

Ruby PHP Python

for x in 0..10 puts 'The number is: %d' % [x]end

Thursday, October 10, 13

(0..10).each do |x| puts "The number is: #{x}"end

<?php for ($x=0; $x<=10; $x++){ echo "The number is: $x";}?>

for x in range(0, 11): print 'The number is: %d' % (x)

Ruby PHP Python

for x in 0..10 puts 'The number is: %d' % [x]end

0.upto(10).each { |x| printf('The number is: %d', x)}

Thursday, October 10, 13

(0..10).each do |x| puts "The number is: #{x}"end

<?php for ($x=0; $x<=10; $x++){ echo "The number is: $x";}?>

for x in range(0, 11): print 'The number is: %d' % (x)

Ruby PHP Python

for x in 0..10 puts 'The number is: %d' % [x]end

0.upto(10).each { |x| printf('The number is: %d', x)}

11.times do |x| puts "The number is: #{x}"end

Thursday, October 10, 13

(0..10).each do |x| puts "The number is: #{x}"end

<?php for ($x=0; $x<=10; $x++){ echo "The number is: $x";}?>

for x in range(0, 11): print 'The number is: %d' % (x)

Ruby PHP Python

for x in 0..10 puts 'The number is: %d' % [x]end

0.upto(10).each { |x| printf('The number is: %d', x)}

11.times do |x| puts "The number is: #{x}"end

puts (0..10).map{|x| "The number is: #{x}"}

Thursday, October 10, 13

(0..10).each do |x| puts "The number is: #{x}"end

<?php for ($x=0; $x<=10; $x++){ echo "The number is: $x";}?>

for x in range(0, 11): print 'The number is: %d' % (x)

Ruby PHP Python

for x in 0..10 puts 'The number is: %d' % [x]end

0.upto(10).each { |x| printf('The number is: %d', x)}

11.times do |x| puts "The number is: #{x}"end

puts (0..10).map{|x| "The number is: #{x}"}

puts ("The number is N\n" * 11).gsub('N').with_index{|_,i| i}

Thursday, October 10, 13

RUBY 2.0Thursday, October 10, 13

KEYWORD ARGUMENTI# Ruby < 2def run(options = {}) options.reverse_merge!( opt1: "default" ) raise ArgumentError unless options.keys.in?([:opt1, :opt2]) options[:opt1]end

# Ruby 2def run(opt1: "default", opt2: nil) opt1end

run(opt2: "x")run(opt2: "x", opt3: "y") # ArgumentError

def run(opt1: "default", opt2: nil, **options) opt1end

run(opt2: "x", opt3: "y")

Thursday, October 10, 13

MODULE#PREPEND

Thursday, October 10, 13

class Bar

def hello puts 1 endend

Bar.new.hello

Bar.ancestors๏ BasicObject๏ Kernel๏ Object๏ Bar

Thursday, October 10, 13

class Foo def hello puts 'hello' endend

class Bar < Foo

def hello puts 1 super endend

Bar.new.hello

Bar.ancestors๏ BasicObject๏ Kernel๏ Object๏ Foo๏ Bar

Thursday, October 10, 13

module FooBar def hello puts 2 super endend

class Foo def hello puts 'hello' endend

class Bar < Foo include FooBar def hello puts 1 super endend

Bar.new.hello

Bar.ancestors๏ BasicObject๏ Kernel๏ Object๏ Foo๏ FooBar๏ Bar

Thursday, October 10, 13

module FooBar def hello puts 2 super endend

class Foo def hello puts 'hello' endend

class Bar < Foo include FooBar def hello puts 1 super endend

Bar.new.hello

Bar.ancestors๏ BasicObject๏ Kernel๏ Object๏ Foo๏ FooBar๏ Bar

12hello

Thursday, October 10, 13

module FooBar def hello puts 2 super endend

class Foo def hello puts 'hello' endend

class Bar < Foo prepend FooBar def hello puts 1 super endend

Bar.new.hello

Bar.ancestors๏ BasicObject๏ Kernel๏ Object๏ Foo๏ Bar๏ FooBar

Thursday, October 10, 13

module FooBar def hello puts 2 super endend

class Foo def hello puts 'hello' endend

class Bar < Foo prepend FooBar def hello puts 1 super endend

Bar.new.hello

Bar.ancestors๏ BasicObject๏ Kernel๏ Object๏ Foo๏ Bar๏ FooBar

21hello

Thursday, October 10, 13

LAZY ENUMERATIONS

Thursday, October 10, 13

ENUMERATIONS

[1, 2, 3, 4] .map { |i| i * 2 } # => [2, 4, 6, 8] .take(2) # => [2, 4] .reduce(&:+) # => 6

Thursday, October 10, 13

LAZY

[1, 2, 3, 4] .lazy # => #<Enumerator::Lazy: [1, 2, 3, 4]> .map { |i| i * 2 } # => #<Enumerator::Lazy: [1, 2, 3, 4]>:map> .take(2) # => #<Enumerator::Lazy: #<Enumerator::Lazy: [1, 2, 3, 4]>:map>:take(2)> .reduce(&:+) # => 6

Thursday, October 10, 13

LAZY

(1..Float::INFINITY) .lazy .map { |i| i * 2 } .take(2) .reduce(&:+)

Thursday, October 10, 13

GENERATIONAL GARBAGE COLLECTOR

If you care about GC, just use JRuby.

Thursday, October 10, 13

GENERATIONAL GARBAGE COLLECTOR

If you care about GC, just use JRuby.

switch to JRubyThursday, October 10, 13

RUBY 2.0: REFINEMENTS

Meh.

Thursday, October 10, 13

RUBY 2.1: REFINEMENTSmodule BalkanString refine String do def debalkanize ActiveSupport::Inflector.transliterate(self) end endend

class User < ActiveRecord::Base using BalkanString

def name @name.debalkanize if @name endend

"test".debalkanize # NoMethodError

Thursday, October 10, 13

RUBY ON RAILS

Thursday, October 10, 13

Django146,869 LOC

Rails162,084 LOC

CakePHP147,738 LOC

Lines of code

Thursday, October 10, 13

100% MODULAREN

Thursday, October 10, 13

Rails‣lepilo

‣Model

‣View‣Controller

Thursday, October 10, 13

Rails‣lepilo

‣Model

‣View‣Controller

Thursday, October 10, 13

Rails‣railties 16,017 LOC ‣activesupport 25,710 LOC

‣Model

‣View‣Controller

Thursday, October 10, 13

Rails‣railties‣activesupport‣Model

‣View‣Controller

Thursday, October 10, 13

Rails‣railties‣activesupport‣activemodel 5,694 LOC

‣activerecord 53,435 LOC

‣View‣Controller

Thursday, October 10, 13

Rails‣railties‣activesupport‣activemodel‣activerecord‣View‣Controller

Thursday, October 10, 13

Rails‣railties‣activesupport‣activemodel‣activerecord‣actionview 22,501 LOC

‣Controller

Thursday, October 10, 13

Rails‣railties‣activesupport‣activemodel‣activerecord‣actionview‣Controller

Thursday, October 10, 13

Rails‣railties‣activesupport‣activemodel‣activerecord‣actionview‣actionpack 35,538 LOC

Thursday, October 10, 13

Rails‣railties‣activesupport‣activemodel‣activerecord‣actionview‣actionpack

Thursday, October 10, 13

DEPLOY

Unicorn

Rainbows!

Thursday, October 10, 13

RAILS 4

Thursday, October 10, 13

TURBOLINKSVideo (57:10)

Rails Conf 2013 Patterns of Basecamp's Application Architecture by David Heinemeier Hansson

http://www.youtube.com/watch?v=yhseQP52yIY

Thursday, October 10, 13

THREAD SAFEJBoss, 200 threads, OK

Thursday, October 10, 13

DON’T JUST TRY, TRY!# Rails 3

[10].try(:count) # => 15.try(:count) # NoMethodErrornil.try(:count) # => nil

# Rails 4

5.try(:count) # => nil5.try!(:count) # NoMethodErrornil.try(:count) #=> nilnil.try!(:count) #=> nil

Thursday, October 10, 13

ACTIONCONTROLLER::LIVEclass MyController < ActionController::Base include ActionController::Live

def stream response.headers['Content-Type'] = 'text/event-stream' 100.times { response.stream.write "hello world\n" sleep 1 } ensure response.stream.close endend

avtomatsko naredi thread

Thursday, October 10, 13

POSTGRESQLArray

Thursday, October 10, 13

POSTGRESQL ARRAY

class CreateDocuments < ActiveRecord::Migration def change create_table :documents do |t| t.string :title t.string :tags, array: true, default: [] t.timestamps end endend

Thursday, October 10, 13

POSTGRESQL ARRAY

Document.create(title: "PostgreSQL", tags: ["pg","rails"])Document.where("'pg' = ANY (tags)")

Thursday, October 10, 13

POSTGRESQLhstore (Hash/Dictionary)

Thursday, October 10, 13

POSTGRESQL HSTORE

class AddHstoreExtension < ActiveRecord::Migration def up execute 'CREATE EXTENSION hstore' end

def down execute 'DROP EXTENSION hstore' endend

class AddPropertiesToComics < ActiveRecord::Migration def change add_column :comics, :properties, :hstore endend

Thursday, October 10, 13

POSTGRESQL HSTORE

class Comic < ActiveRecord::Baseend

Comic.create(properties: { issued: 1.year.ago })

Comic.where("properties -> 'issued' > ?", 2.years.ago)

Thursday, October 10, 13

POSTGRESQL HSTORE

class Comic < ActiveRecord::Base store_accessor :properties, :issuedend

Comic.create(issued: 1.year.ago)

Comic.where("properties -> 'issued' > ?", 2.years.ago)

Ali sploh rabiš hstore v tem primeru?Thursday, October 10, 13

ACTIVERECORDIn Rails 4

Thursday, October 10, 13

SCOPES

class User < ActiveRecord::Base # Rails 3 scope :newest, where("created_at > ?", 1.week.ago)

# Rails 4 scope :newest, -> { where("created_at > ?", 1.week.ago) }end

Thursday, October 10, 13

WHERE.NOT

# Rails 3User.where('role != ?', 'admin')User.where('nickname IS NOT NULL')

# Rails 4User.where.not(role: 'admin')User.where.not(nickname: nil)

Thursday, October 10, 13

MIGRACIJE PREJclass ChangeProductsPrice < ActiveRecord::Migration def up change_table :products do |t| t.change :price, :string end end

def down change_table :products do |t| t.change :price, :integer end endend

Thursday, October 10, 13

MIGRACIJEclass ChangeProductsPrice < ActiveRecord::Migration def change reversible do |dir| change_table :products do |t| dir.up { t.change :price, :string } dir.down { t.change :price, :integer } end end endend

Thursday, October 10, 13

NONE RELATIONclass User < ActiveRecord::Base scope :with_role, ->(role) { if User.role_valid? role where(role: role) else none end }end

User.with_role(params[:role]).where.not(nick: nil)

Thursday, October 10, 13

STRONG PARAMETERS

Thursday, October 10, 13

PROBLEM

• User

• name

• is_admin

Thursday, October 10, 13

RAILS 3class User < ActiveRecord::Base attr_accessible :nameend

# controller

user.update_attributes(params[:user])

# admin

user.update_attributes(is_admin: true) # :-(

user.is_admin = trueuser.save

Thursday, October 10, 13

RAILS 3

class User < ActiveRecord::Base attr_accessible :nameend

# controller

user.update_attributes(params[:user])

v čem je v resnici problem?

Thursday, October 10, 13

RAILS 3

class User < ActiveRecord::Base attr_accessible :nameend

# controller

user.update_attributes(params[:user])

user.update_attributes(is_admin: true) # :-(

non-sanitizeduser input

Thursday, October 10, 13

STRONG PARAMETERS

class User < ActiveRecord::Baseend

# controller

def user_params params.require(:user).permit(:name)end

user.update_attributes(user_params)

user.update_attributes(params[:user])# error: Unpermitted parameters

user.update_attributes(is_admin: true) # OK :-)

Thursday, October 10, 13

CACHING

• avtomatski expire pri spremembi modela

• avtomatski expire pri spremembi viewa

• russian doll (nested) caching

• Rails Conf 2013 Patterns of Basecamp's Application Architecture by David Heinemeier Hansson

• http://www.youtube.com/watch?v=yhseQP52yIY

Thursday, October 10, 13

ACTIVESUPPORT::CONCERNmodule Commentable extend ActiveSupport::Concern

included do has_many :comments end

def has_comments? !comments.empty? end

module ClassMethods def comments_count joins(:comments) .references(:comments) .pluck("COUNT(comments.id)") end endend

class Post < ActiveRecord::Base include Commentableend

User.posts.comment_countPost.first.commentsPost.first.has_comments?

Rails 4 ima direktorij za concerne.Whatever.

Thursday, October 10, 13

THE END

Thursday, October 10, 13