Computer >> Máy Tính >  >> Lập trình >> Ruby

Bạn nên sử dụng Phạm vi hoặc Phương pháp Lớp?

Bài báo này cũng có sẵn bằng tiếng Hàn, cảm ơn Soonsang Hong!

Phạm vi là một cách tuyệt vời để lấy đúng đối tượng ra khỏi cơ sở dữ liệu của bạn:

app / models / review.rb
class Review < ActiveRecord::Base
  scope :most_recent, -> (limit) { order("created_at desc").limit(limit) }
end

Bạn sẽ sử dụng phạm vi như sau:

app / models / Home_controller.rb
@recent_reviews = Review.most_recent(5)

Tuy nhiên, việc gọi phạm vi đó trông chính xác như gọi một phương thức lớp trên Review . Và thật dễ dàng để xây dựng nó dưới dạng một phương thức lớp, thay vào đó:

app / models / review.rb
def self.most_recent(limit)
  order("created_at desc").limit(limit)
end
app / controllers / Home_controller.rb
@recent_reviews = Review.most_recent(5)

Vậy tại sao bạn lại sử dụng phạm vi khi bạn có thể sử dụng các phương thức lớp Ruby thông thường? Có đáng để giữ những khái niệm hoàn toàn riêng biệt, nhưng tương đương, trong đầu bạn không? Điều gì sẽ xảy ra nếu bạn gặp phải những lỗi kỳ lạ? Có phải tất cả những thứ bổ sung này không phải là thứ khiến Rails khó học hơn sao?

Khi nào sẽ sử dụng một phạm vi thay vì một phương thức lớp có hợp lý không?

Tại sao lại sử dụng phạm vi khi chúng ta đã có các phương thức lớp?

Điều gì sẽ xảy ra nếu bạn muốn lấy tất cả các bài đánh giá được viết sau một ngày cụ thể? Nhưng nếu không có ngày nào được chỉ định, bạn muốn tất cả các bài đánh giá được trả lại thay thế?

Dưới dạng một phạm vi, có dạng như sau:

app / models / review.rb
scope :created_since, ->(time) { where("reviews.created_at > ?", time) if time.present? }

Đủ dễ dàng, phải không? Còn phương thức lớp thì sao?

app / models / review.rb
def self.created_since(time)
  if time.present?
    where("reviews.created_at > ?", time)
  else
    all
  end
end

Cần phải làm thêm một chút. Các phạm vi thích trả lại các phạm vi, vì vậy chúng dễ dàng liên kết với nhau:

Review.positive.created_since(5.days.ago)

Nhưng để phương thức lớp hoạt động theo cách tương tự, bạn phải xử lý cụ thể trường hợp thời gian là con số không. Nếu không, người gọi sẽ phải tìm ra liệu nó có phạm vi hợp lệ, có thể chia sẻ được hay không.

Các phương thức luôn trả về cùng một loại đối tượng thực sự hữu ích . Bạn không phải lo lắng nhiều về các trường hợp hoặc lỗi cạnh. Bạn có thể cho rằng mình sẽ luôn được trao lại một đồ vật mà bạn có thể sử dụng.

Ở đây, điều đó có nghĩa là bạn có thể xâu chuỗi các phạm vi lại với nhau mà không phải lo lắng về nil giá trị quay trở lại.

Vẫn có những cách bạn có thể phá vỡ giả định rằng bạn luôn lấy lại phạm vi:

app / models / review.rb
scope :broken, -> { "Hello!!!" }
irb(main):001:0> Review.broken.most_recent(5)
NoMethodError: undefined method `most_recent' for "Hello!!!":String

Nhưng tôi chưa bao giờ có điều đó xảy ra trong mã thực.

Điều tôi yêu thích nhất về phạm vi là chúng thể hiện ý định . Bạn đang nói với người tiếp theo đọc mã của bạn, "Phương pháp này có thể được xâu chuỗi, cuối cùng sẽ chuyển thành danh sách các đối tượng và sẽ giúp bạn chọn đúng nhóm đối tượng." Đó là nhiều điều hơn một phương thức lớp chung chung cho biết.

Khi nào bạn nên sử dụng phương thức lớp thay vì phạm vi?

Vì phạm vi thể hiện rõ mục đích, tôi sử dụng chúng bất cứ khi nào tôi xâu chuỗi các phạm vi đơn giản, được tích hợp sẵn (như wherelimit ) vào các phạm vi phức tạp hơn . Tìm đúng nhóm đối tượng là phạm vi được thiết kế cho.

Có hai ngoại lệ:

  1. Khi tôi cần tải trước các phạm vi, thay vào đó, tôi chuyển chúng thành các liên kết .
  2. Khi tôi thực hiện nhiều hơn các phạm vi tích hợp trong chuỗi thành các phạm vi lớn hơn, tôi sử dụng các phương thức lớp .

Khi logic phạm vi của bạn trở nên phức tạp, một phương thức lớp có vẻ như là nơi thích hợp để đặt nó.

Bên trong một phương thức lớp, bạn có thể dễ dàng trộn mã Ruby với mã cơ sở dữ liệu. Nếu bạn có mã sắp xếp dễ viết hơn trong Ruby, bạn có thể lấy các đối tượng của mình theo thứ tự mặc định của chúng và sử dụng sort_by để sắp xếp chúng theo đúng thứ tự.

Hoặc, nếu bạn cảm thấy đặc biệt phức tạp, một phương thức lớp có thể lấy dữ liệu từ một số nơi khác nhau:cơ sở dữ liệu của bạn, Redis hoặc một API hoặc dịch vụ bên ngoài. Sau đó, nó có thể tập hợp tất cả thành một bộ sưu tập các đối tượng mà cảm thấy giống như một phạm vi được chuyển thành một mảng.

Ngay cả khi đó, bạn vẫn nên đặt mã lựa chọn, sắp xếp, tham gia và lọc của mình vào trong các phạm vi. Sau đó, sử dụng phạm vi bên trong phương thức lớp của bạn. Bạn sẽ kết thúc với một phương pháp lớp rõ ràng hơn và phạm vi bạn có thể sử dụng trong toàn bộ ứng dụng của mình.

Phạm vi là một trong những tính năng Rails yêu thích của tôi. Bạn có thể thực hiện một số công việc mạnh mẽ - đọc bài viết của tôi về sắp xếp và lọc các mô hình Rails để xem ví dụ về phạm vi đặc biệt hữu ích.

Và có một cách thực sự đơn giản để sử dụng phạm vi thành thạo:chơi với chúng trong các ứng dụng nhỏ, tập trung. Chương mẫu miễn phí về Thực hành Đường ray sẽ chỉ cho bạn cách thực hiện. Kiểm tra nó ra!