Rails 5 Tips Có Lẽ Bạn Chưa Biết

Hash#dig

Có thể bạn đã gặp qua 1 đoạn code tương tự như thế này:

... if params[:user] && params[:user][:address] && params[:user][:address][:somewhere_deep]

Code như trên đúng là chưa đẹp cho lắm? đó là khi bạn chưa biết đến dig rồi, hãy coi dig tương tự toán tử an toàn & đối với các đối tượng Hash, bạn có thể viết lại đoạn code trên như thế này.

... if params.dig(:user, :address, :where_deep)

Object#presence_in

presence_in cho phép bạn thay thế các điều kiện (thường là toán tử bậc 3). Ví dụ: mã của bạn trông giống như:

sort_options = [:by_date, :by_title, :by_author] 
sort = (sort_options.include?(params[:sort]) && params[:sort]) || :by_date

// tương tự 
sort = (sort_options.include?(params[:sort]) && params[:sort]) || :by_date

Còn khi dùng presence_in

params[:sort].presence_in(sort_options) || :by_date

Module#alias_attribute

Cho phép bạn tạo aliases cho các thuộc tính, bao gồm getter, setter và một predicate

class Person
  include ActiveModel::AttributeMethods

  attr_accessor :name
  attribute_method_suffix '_short?'
  define_attribute_methods :name

  alias_attribute :nickname, :name

  private

  def attribute_short?(attr)
    send(attr).length < 5
  end
end

person = Person.new
person.name = 'Bob'
person.name            # => "Bob"
person.nickname        # => "Bob"
person.name_short?     # => true
person.nickname_short? # => true

Module#delegate

Delegate giúp dễ dàng gọi các public methods của object khác giống như là của chính mình, đặc biệt với các models có quan hệ phức tạp thì bạn có thể thực hiện gọi từ một class đến nhiều class khác.

Vd:

class User < ActiveRecord::Base
  has_one :profile
end
class Profile < ApplicationRecord
  belongs_to :user
end

Thay vì bình thường ta gọi thuộc tính name của user bằng cách

user.profile.name

Thì giờ với delegate ta có thể lấy bằng cách

delegate :name, to: :profile

// và gọi bằng lệnh
user.name 

Nếu muốn lấy nhiều thuộc tính của user

delegate :name, :email, to: :profile

Bạn cũng có thể custom prefix :

delegate :name, :email, to: :profile, prefix: :user

// lúc này các sẽ gọi các method bằng cách thêm tiền tố user_ phía trước user_name, user_email

Single *Splat And Double **Splat Operator

Single *Splat

Toán tử Splat, * để đơn giản hóa gán các toán giá trị của một mảng ứng với từng biến:
Vd:

ex_1
t,o,p,t,a,l = *(1..6) #=> [1, 2, 3, 4, 5, 6]
puts p #=> 3

ex_2
first, *rest, last  = ["a", "b", "c", "d"]

puts first #=> "a"
puts rest #=> ["b", "c"]
puts last #=> "d"

chúng ta cũng có thể sử dụng trên các object khác

Toptaller = Struct.new(:name, :tech)
toptaller = Toptaller.new("Eqbal", "Ruby")
name, tech = *toptaller
puts tech #=> Ruby

Double **Splat

Với double splat nó hoạt động cũng giống như splat nhưng đối với các keyword, nó trả về một Hash với key: value

def doublesplat(args, *others, **hash_args)
  [args, others, hash_args]
end

result

> doublesplat 10
=> [10, [], {}]
> doublesplat 10, 20, 30
=> [10, [20, 30], {}]
> doublesplat 10, 20, 30, a: 40, b: 50
=> [10, [20, 30], {:a=>40, :b=>50}]
> doublesplat 10, d: 40, e: 50
=> [10, [], {:d=>40, :e=>50}]

Nguồn

https://www.freecodecamp.org/news/rubys-splat-and-double-splat-operators-ceb753329a78/
https://hackernoon.com/5-ruby-on-rails-tips-you-probably-dont-know-8b80b4a0890f
https://api.rubyonrails.org/classes/Module.html#method-i-delegate


All Rights Reserved