Các mẹo hữu ích khi code Ruby
Bài đăng này đã không được cập nhật trong 7 năm
Trong lúc lập trình ta luôn muốn code sao cho thật ngắn gọn và tối ưu nhất có thể. Để có thể dễ đọc, dễ nâng cấp và sửa đổi 1 cách dễ dàng. Bài viết này mình xin giới thiệu một số mẹo nhỏ khi code Ruby. Hi vọng bài viết sẽ giúp ích cho bạn
1. Sử dụng &. thay cho try
Giả sử bạn có 1 account và muốn kiểm tra xem chủ nhân của account đó có địa chỉ hay không. Để an toàn ta thường viết:
if account && account.owner && account.owner.address
...
end
Nhưng đoạn code này khá dài dòng. Để rút gọn hơn ta có thể viết:
if account.try(:owner).try(:address)
...
end
Nó sẽ trả về nil nếu owner không tồn tại hoặc address nil. Chúng ta có thể viết lại đoạn code này cho an toàn hơn bằng cách sử dụng &.
if account&.owner&.address
...
end
Đoạn code này ngắn nhất và tối ưu nhất cho trường hợp trên.
Chúng ta cùng tổng hợp lại qua ví dụ
account = Account.new(owner: nil) # account without an owner
account.owner.address
# => NoMethodError: undefined method `address' for nil:NilClass
account && account.owner && account.owner.address
# => nil
account.try(:owner).try(:address)
# => nil
account&.owner&.address
# => nil
Kết quả trả về giống nhau nhưng chúng ta có thể dùng nhiều cách khác nhau để diễn đạt chúng
2. Sử dụng dig trong try hash
Thay vì phải viết
address = params[:account].try(:[], :owner).try(:[], :address)
# hoặc
address = params[:account].fetch(:owner) .fetch(:address)
Ta có thể dễ dàng sử dụng Hash#dig với chức năng tương tự như trên
address = params.dig(:account, :owner, :address)
3. Sử dụng render view partials
Ở trong controller
ta có action index lấy tất cả toàn bộ user ra
# app/controllers/users_controller.rb
def index
@users = User.all
end
Ở view thay vì ta viết như thế này
<% @users.each do |user| %>
<p><%= user.name %></p>
<p><%= user.email %></p>
<% end %>
Ta có thể thay thế dùng render partial Tạo 1 file chứa thông tin của user
# app/views/users/_user.html.erb
<p><%= user.name %></p>
<p><%= user.email %></p>
Rồi trong file index ta chỉ việc
<%= render @users %>
Thật nhanh gọn phải không. Bạn có thể tham khảo thêm các option ở Partial Render
4. Sử dụng tap
Cho đối tượng vào 1 block và return ra chính đối tượng đó. Để dễ hiểu hơn ta có thể tìm hiểu nó qua ví dụ Ví dụ bạn muốn tạo 1 params. Thay vì viết
def user_params
params = {}
..
params[:name] = "ABC"
params[:email] = "XYZ"
params
end
Ta có thể dùng tap
để trả về luôn params
def user_params
{}.tap do |params|
params[:name] = "ABC"
params[:email] = "XYZ"
end
end
Tương tự ta có thể sử dụng với mảng []
, đối tượng...vv..
Cập nhập hoặc tạo mới đối tượng có các thuộc tính chỉ định
class User < ActiveRecord::Base
class << self
def create_or_update(locale, address, attributes)
find_or_initialize_by(locale: locale, address: address).tap do |target|
target.attributes = attributes
target.save!
end
end
end
end
5. Tạo nhiều bản ghi cùng 1 lúc
Ví dụ ta cần tạo nhiều bản ghi cùng 1 lúc với các giá trị khác nhau. Không thể dùng foreach
rồi insert
lần lượt được. như vậy performance sẽ rất chậm. Mình xin giới thiệu 1 cách khá hay ho. Ví dụ tạo nhiều bản ghi user_books
cùng chung user_id
chỉ khác book_id
. Ta dùng gem ActiveRecord-import
kết hợp với product
book_ids = [1, 2, 3, 4]
user_id = 1
user_books = [user_id].product book_ids
=> trả về 1 mảng params id: [[1, 1], [1, 2], [1, 3], [1, 4]]
# Sau đó ta import vào DB
UserBook.import( :user_id, :book_id], user_books)
6. Tìm ra phần tử thay đổi thuộc tính, phần tử bị xóa, phần tử mới
Ví dụ ta muốn kiểm tra params gửi lên server có bao nhiêu phần tử thay đổi thuộc tính, bao nhiêu phần tử bị xóa, bao nhiêu phần tử mới ta có thể làm theo cách sau:
Đầu tiên ta dùng assign_attributes
gán cho đối tượng params
reservation = reservation.assign_attributes(nested_params)
# Lấy ra room mới
new_rooms = reservation.eservation_rooms.select(&:new_record?)
# Lấy ra room bị xóa
marked_destroy_rooms = reservation.reservation_rooms.select(&:marked_for_destruction?)
# Lấy ra room thay đổi thông tin
changed_rooms = reservation.rservation_rooms.select(&:changed?)
5. Các mẹo với Array
Trong lúc làm việc với array có rất nhiều hàm mình hay sử dụng, hôm nay mình xin liệt kê 1 số hàm có thể hữu ích với bạn.
- Sử dụng
compact
để loại đi những phần tửnil
[1, 2, nil, nil].compact
=> [1, 2]
- Loại bỏ các phần tử trùng nhau với
uniq
[1, 1, 2, 2, 4, 0].uniq
=> [1, 2, 4, 0]
- Đảo ngược phần tử trong mảng
arr = [1, 2, 3, 4]
arr.reverse
=> [4, 3, 2, 1]
- Tìm ra phần tử chung giữa 2 mảng
[1, 3, 4] & [4, 2, 7]
=> [4]
- Duyệt phần tử trong mảng
- Dùng
each
để duyệt các phần tử trong mảng
arr = [1, 2, 3, 4]
arr.each do |value|
put "#{value}! "
end
=> 1! 2! 3! 4!
- Dùng
map
để thực hiện các phép toán trong mảng
[1, 2, 3, 4].map{|val| val + 1}
=> [2, 3, 4, 5]
- Dùng
select
để lấy phần tử có điều kiện: Lấy các phần tử lớn hơn 1
[1, 2, 3, 4].select{|val| val > 1}
=> [2, 3, 4]
- Dùng
count
để đếm phần tử có điều kiện: Đếm các phần tử có giá trị lớn hơn 1
[1, 2, 3, 4].count{|val| val > 1}
=> 3
Bạn có thể tham khảo các phương thức khác ở Array
4. Các mẹo với Hash
has_key?(key)
và ``has_value?(value): Kiểm tra trong hash có key hoặc có value không
h = { "a" => 100, "b" => 200 }
h.has_value?(100) #=> true
h.has_value?(999) #=> false
h.has_key?("a") #=> true
h.has_key?("c") #=> false
- Gộp 2 hash với nhau với
merge
h1 = { "a" => 100, "b" => 200 }
h2 = { "b" => 254, "c" => 300 }
h1.merge(h2) #=> {"a"=>100, "b"=>254, "c"=>300}
- . Duyệt phần tử trong mảng cũng giống như Array mình viết bên trên chỉ khác thay vì
each do |value|
thì chúng ta thay bằngeach do |key, value|
Bạn có thể tham khảo thêm tại Hash
Hi vọng bài viết có giúp ích cho bạn.
All rights reserved