Yang Baru Pada Rails 5

Akhir tahun 2015 Ruby on Rails 5 Beta 1 dirilis. Tidak lama kemudian dirilis Rails versi Beta 1.1 dan awal Februari 2016 dirilis Rails 5 Beta 2. Perubahan versi major dari Rails diikuti banyak perubahan.

Pada tulisan akan dibahas beberapa fitur baru Rails 5 dan mungkin dilanjutkan tulisan lain mengenai Rails 5.

Action Cable
Fitur Action Cable memungkinkan Rails 5 memberikan support terhadap WebSocket, hal ini mempermudah dalam membuat aplikasi real time. Awalnya sempat menjadi kontroversi karena adanya dependensi terhadap Celluloid, Redis, serta EventMachine.

Namun pada rilis Rails 5 Beta 2 dependensi tersebut dihilangkan. Sebagai gantinya Rails menggunakan adapter alternatif ke Redis sebagai pubsub dan menggunakan non-EventMachine adapter Redis. Selain itu, pada rilis ini Rails resmi tidak lagi support PostgreSQL dibawah versi 9.1.

Rails juga memperkenalkan ActionController::Renderer dimana memungkinkan untuk melakukan render template diluar controller. Sangat berguna ketika ingin reuse template dari server-side sebagai respon WebSocket.

Demo Action Cable oleh DHH

Rails API
Fitur selanjutnya dari Rails 5 adalah Rails API. Fitur ini memungkinkan untuk generate aplikasi API-only dimana aplikasi yang dihasilkan generator Rails mengasumsikan menggunakan JSON sebagai respon serta menghilangkan bagian — bagian yang tidak digunakan ketika membuat aplikasi pure hanya sebagai backend.

[code language=”bash”]
rails new my-awesome-api-app — api
[/code]

Rails Command
Bagi pemula sepertinya banyak yang mengalami kebingungan tentang rake terkait perbedaan dengan command rails. Dengan adanya perubahan pada Rails Command, pada Rails 5 semua command yang menggunakan rake akan diganti menjadi rails. Sehingga perintah seperti rake db:migrate akan diganti menjadi rails db:migrate.

Attributes API
Fitur Attributes API digunakan untuk mendefinisikan type pada Model dan memungkinkan untuk melakukan override attribute yang ada jika diperlukan. Fitur ini juga memungkinkan untuk mendefinisikan attribute tanpa memiliki kolom database.

[code language=”ruby”]
# Contoh 1
# db/schema.rb
create_table :store_listings, force: true do |t|
t.decimal :price_in_cents
end

# app/models/store_listing.rb
class StoreListing < ActiveRecord::Base
end

store_listing = StoreListing.new(price_in_cents: ‘9.1’)

# sebelum Rails 5
store_listing.price_in_cents # => BigDecimal.new(9.1)

class StoreListing < ActiveRecord::Base
attribute :price_in_cents, :integer
end

# Rails 5
store_listing.price_in_cents # => 9

# Contoh 2
# Attribute tanpa kolom di database

class MyModel < ActiveRecord::Base
attribute :my_string, :string
attribute :my_int_array, :integer, array: true
attribute :my_float_range, :float, range: true
end

model = MyModel.new(
my_string: “string”,
my_int_array: [“11”, “12”, “13”],
my_float_range: “[2,4.5]”,
)

model.attributes
# =>
# {
# my_string: “string”,
# my_int_array: [11, 12, 13],
# my_float_range: 2.0..4.5
# }
[/code]

ApplicationRecord
ApplicationRecord mirip ApplicationController. Superclass ini bertujuan untuk berbagi fungsionalitas yang sama di semua model sehingga tidak diperlukan lagi monkey patch terhadap ActiveRecord::Base.

[code language=”ruby”]
module MyCustomValidationModule
def do_something
puts “Yadaaa! Yadaa!”
end
end

# sebelum Rails 5
ActiveRecord::Base.include(MyCustomValidationModule)

# Rails 5
class ApplicationRecord < ActiveRecord::Base
include MyCustomValidationModule

self.abstract_class = true
end
[/code]

ActiveRecord::Relation#or
ActiveRecord::Relation#or memungkinkan melakukan query #or.

[code language=”ruby”]
Post.where(id: 1).or(Post.where(id: 2))
# => SELECT * FROM posts WHERE (id = 1) OR (id = 2)

# Sayang masih belum support untuk syntax seperti ini.
Post.where(id: 1).or(id: 2)
# NoMethodError: undefined method `limit_value’ for {:id=>2}:Hash
[/code]

ActiveRecord::Relation#in_batches
Method ActiveRecord::Relation#in_batches memungkinkan melakukan proses terhadap batch atau sekumpulan record sekaligus.

[code language=”ruby”]
# dalam block
User.where(“age > 25”).in_batches do |relation|
relation.delete_all
sleep(10) # Throttle the delete queries
end

# tanpa block
User.in_batches.delete_all
User.in_batches.update_all(mantap: true)
User.in_batches.each_record(&:count_sign_in!)
[/code]

Options dari ActiveRecord::Relation#in_batches

  • of — Set ukuran batch. Default 1000.
  • load — Set apakah relation harus di-load. Default false.
  • start — Set berapa nilai primary key untuk memulai batches. Angka yang dimasukkan merupakan inklusif.
  • finish — Set berapa nilai primary key untuk bacthes berakhir. Angka yang dimasukkan merupakan inklusif.

Dengan adanya fitur dan options diatas, sangat berguna ketika harus melakukan update record per kelompok (batches). Juga sangat berguna ketika ada beberapa worker yang memproses queue yang sama dimana worker 1 memproses record dengan ID 1 sampai 1000, worker 2 dengan ID 1001 sampai 2000, dan seterusnya.

[code language=”ruby”]
User.in_batches(of: 2000, start: 1000).update_all(awesome: true)

User.in_batches.each do |relation|
relation.update_all(‘age = age + 5’)
relation.where(‘age > 25’).update_all(awesome: true)
relation.where(‘age <= 25’).delete_all
end
[/code]

ActiveRecord::Base#has_secure_token
Fitur Rails ini memungkinkan untuk melakukan generate token unik pada model. Sangat berguna ketika membangun API dimana sering membutuhkan unique token yang digunakan sebagai authentication token.

Token unik yang di-generate sepanjang 24 karakter dengan menggunakan SecureRandom::base58. Kemungkinan terjadi token kembar masih ada.

[code language=”ruby”]
# Schema: User(token:string, auth_token:string)
class User < ActiveRecord::Base
has_secure_token
has_secure_token :auth_token
end

user = User.new
user.save
user.token # => “ZM27zsMN2ViQKta1bGfLmVs9”
user.auth_token # => “99TMHrHJFvFDwodq8w7Ev2y3”
user.regenerate_token # => true
user.regenerate_auth_token # => true
[/code]

Method find(ids)
Sebelum Rails 5, ketika melakukan find(ids) atau where(ids: array_of_id), record yang dihasilkan tidak berurutan sesuai ID yang diberikan. Pada Rails 5 secara default akan diurutkan berdasarkan id yang dimasukkan.

[code language=”ruby”]
ids = [3, 4, 2, 5]

# sebelum Rails 5
posts = Post.find(ids)
ordered_posts = ids.collect do |id|
posts.detect {|post| post.id == id }
end

# Rails 5
posts = Post.find(ids)
[/code]

ActiveModel::Errors#details

[code language=”ruby”]
class User < ActiveRecord::Base
validates :email, presence: true
end

user = User.new
user.valid?
user.errors.details
# => {email: [{error: :blank}]}
[/code]

Multiple Konteks pada valid? dan invalid?

[code language=”ruby”]
class User
include ActiveModel::Validations

attr_reader :email, :name
validates_presence_of :email, on: :create
validates_presence_of :name, on: :update
end

user = User.new
user.valid?([:create, :update]) # => false
user.errors.messages # => {:email=>[“can’t be blank”], :name=>[“can’t be blank”]}
[/code]

Callback Baru: after_{create,update,delete}_commit

[code language=”ruby”]
# Sebelum Rails 5

after_commit :add_to_index_later, on: :create
after_commit :update_in_index_later, on: :update
after_commit :remove_from_index_later, on: :destroy

# Rails 5
after_create_commit :add_to_index_later
after_update_commit :update_in_index_later
after_destroy_commit :remove_from_index_later
[/code]

Perubahan ActiveRecord::Relation#update

Pada Rails 5 bisa melakukan banyak record tanpa mengirimkan id dari record yang akan di-update.

[code language=”ruby”]
# Sebelum Rails 5
# ArgumentError: wrong number of arguments (1 for 2)
Post.where(published: true).update(body: “Group of Software Engineer”)

# Rails 5
# OK
Post.where(published: true).update(body: “Group of Software Engineer”)
[/code]

Terakhir, Rails 5 hanya support versi Ruby 2.2.2 atau lebih baru, jadi sebelum update Rails pastikan update Ruby terlebih dahulu.

Referensi

Sumber

Related Posts

Part II — Understanding about RuleChain

Mengenal dasar RxSwift

Making Backward Compatible Adaptive Colors for Dark Mode in iOS

Automate Your Android App Bundle Publishing using Jenkins

No Comment

Leave a Reply