rails/rails — pull request #14706 by Sharangovich (2014-04-11 13:06:49+00:00)
Title: New '#read_attributes' method added to ActiveRecord

The continuation of this pull request https://github.com/rails/rails/pull/14683.
Some numbers:
```console
# Migration for used model
class CreateUsers < ActiveRecord::Migration
def change
create_table :users do |t|
t.string "first_name"
t.string "last_name"
t.string "middle_name"
t.string "phone_number"
t.text "summary"
t.string "encrypted_password", default: "", null: false
t.datetime "remember_created_at"
t.integer "sign_in_count", default: 0
t.datetime "current_sign_in_at"
t.datetime "last_sign_in_at"
t.string "current_sign_in_ip"
t.string "last_sign_in_ip"
t.string "authentication_token"
t.string "login"
t.string "time_zone"
t.string "reset_password_token"
t.datetime "reset_password_sent_at"
t.timestamps
end
end
end

# Method to measure many times and get average
def measure_read(&block); results=(1..1000).map{ Benchmark.measure{ yield }.real }; (results.sum / results.size).to_f; end

# Reading 2 attributes, about 3 times faster
2.1.0 :091 > measure_read{ u.attributes.slice('last_name', 'phone_number') }
=> 2.220099999999981e-05
2.1.0 :092 > measure_read{ u.read_attributes('last_name', 'phone_number') }
=> 6.6989999999998684e-06

# Reading 3 attributes, bit more then 2 times faster
2.1.0 :090 > measure_read{ u.attributes.slice('last_name', 'phone_number', 'created_at') }
=> 2.2799999999999843e-05
2.1.0 :089 > measure_read{ u.read_attributes('last_name', 'phone_number', 'created_at') }
=> 1.0906000000000014e-05

# Reading 5 attributes, bit more then 2 times faster
2.1.0 :094 > measure_read{ u.attributes.slice('first_name', 'last_name', 'middle_name', 'phone_number', 'created_at') }
=> 2.1727999999999823e-05
2.1.0 :093 > measure_read{ u.read_attributes('first_name', 'last_name', 'middle_name', 'phone_number', 'created_at') }
=> 9.517000000000182e-06

# Reading 8 attributes, about one and a half times faster
2.1.0 :096 > measure_read{ u.attributes.slice('first_name', 'last_name', 'middle_name', 'phone_number', 'created_at', 'summary', 'login', 'timezone') }
=> 2.67580000000002e-05
2.1.0 :095 > measure_read{ u.read_attributes('first_name', 'last_name', 'middle_name', 'phone_number', 'created_at', 'summary', 'login', 'timezone') }
=> 1.7084000000000147e-05

# Reading 13 attributes, about one and a half times faster
2.1.0 :098 > measure_read{ u.attributes.slice('first_name', 'last_name', 'middle_name', 'phone_number', 'created_at', 'summary', 'login', 'timezone', 'encrypted_password', 'remember_created_at', 'sign_in_count', 'current_sign_in_at', 'last_sign_in_at') }
=> 2.937400000000012e-05
2.1.0 :097 > measure_read{ u.read_attributes('first_name', 'last_name', 'middle_name', 'phone_number', 'created_at', 'summary', 'login', 'timezone', 'encrypted_password', 'remember_created_at', 'sign_in_count', 'current_sign_in_at', 'last_sign_in_at') }
=> 2.1439000000000023e-05

# Reading 20 attributes, about one and a half times faster
2.1.0 :099 > measure_read{ u.attributes.slice('first_name', 'last_name', 'middle_name', 'phone_number', 'created_at', 'summary', 'login', 'timezone', 'encrypted_password', 'remember_created_at', 'sign_in_count', 'current_sign_in_at', 'last_sign_in_at', 'current_sign_in_ip', 'last_sign_in_ip', 'authentication_token', 'reset_password_token', 'reset_password_sent_at', 'created_at', 'updated_at') }
=> 3.758899999999996e-05
2.1.0 :100 > measure_read{ u.read_attributes('first_name', 'last_name', 'middle_name', 'phone_number', 'created_at', 'summary', 'login', 'timezone', 'encrypted_password', 'remember_created_at', 'sign_in_count', 'current_sign_in_at', 'last_sign_in_at', 'current_sign_in_ip', 'last_sign_in_ip', 'authentication_token', 'reset_password_token', 'reset_password_sent_at', 'created_at', 'updated_at') }
=> 2.4881999999999963e-05
```
Of course, if you need to get all attributes - using '#attributes' method is much more appropriate.