2012-03-01 30 views
5

Hãy để tôi hình dung điều đó cho bạn.ActiveRecord phát hiện cuộc gọi phương thức cuối cùng trong chuỗi như thế nào?

class Product < ActiveRecord::Base 
end 

Product.first.title 
#=> "My sample product" 

Không có gì đặc biệt ở đây. Chỉ cần một cuộc gọi phương thức đơn giản. Bây giờ hãy xem ví dụ sau.

class Product < ActiveRecord::Base 
    def method_missing 
    end 
end 

Product.first.title 
#=> nil 

Product.first 
Product.first.title 
#=> "My sample product" 

Làm cách nào có thể? Trong một số cách họ xác định sự kết thúc của chuỗi phương pháp và hành động theo đó? Ít nhất đó là lý thuyết của tôi.

Có ai có thể giải thích hành vi này không?

Trả lời

7

Bạn đang thấy một tạo phẩm sử dụng irb để điều tra mọi thứ.

Khi bạn nói điều này:

> Product.first.title 
#=> nil 

bạn method_missing sẽ được gọi để lười biếng nạp phương pháp title và bạn nhận nil.

Khi bạn nói điều này:

> Product.first 

Bạn đang có hiệu quả làm điều này:

> p = Product.first; puts p.inspect 

Thể hiện sản phẩm đầu tiên sẽ được nạp và sau đó irb sẽ gọi inspect vào nó và AR sẽ thêm phương pháp truy cập trên đường đi. Kết quả là Sản phẩm sẽ có phương thức title. Do đó, làm điều này:

> Product.first 
> Product.first.title 

sẽ không gọi method_missing của bạn tại tất cả như sẽ có một phương pháp thực title cho Product.first.title để gọi.

Nếu bạn cố gắng một lần nữa như thế này:

> Product.first; nil 
> Product.first.title 

Bạn sẽ thấy hai nil s.


Theo như chuỗi đi, ActiveRecord không thực sự phát hiện kết thúc, nó chỉ là một số phương pháp gọi tự nhiên yêu cầu dữ liệu thực từ cơ sở dữ liệu và một số thì không.

Nếu bạn gọi where, order hoặc bất kỳ phương pháp truy vấn nào khác, bạn sẽ nhận được cá thể ActiveRecord::Relation và bạn có thể chuỗi các phương pháp truy vấn và phạm vi khác trên đối tượng quan hệ đó. Ví dụ, where (mà ActiveRecord :: Quan hệ được bằng cách bao gồm ActiveRecord::QueryMethods) trông như thế này:

def where(opts, *rest) 
    return self if opts.blank? 

    relation = clone 
    relation.where_values += build_where(opts, rest) 
    relation 
end 

nên nó chỉ làm cho một bản sao của truy vấn hiện tại, bổ sung một số điều cần bản sao, và cung cấp cho bạn các bản sao trở lại.

Nếu bạn gọi first, last, to_a, all, bất kỳ Enumerable phương pháp (ví dụ: bạn gọi each), ...sau đó bạn hỏi về các trường hợp cụ thể và ActiveRecord sẽ phải thực hiện truy vấn để nhận ra (các) cá thể mô hình được đề cập. Ví dụ, ActiveRecord::Relation#to_a trông như thế này:

def to_a 
    logging_query_plan do 
    exec_queries 
    end 
end 

all là ít hơn một wrapper xung quanh to_a. ActiveNecord không thực sự biết nơi mà kết thúc của chuỗi, nó chỉ không tải bất cứ điều gì từ cơ sở dữ liệu cho đến khi nó có để bạn nói với nó nơi chuỗi kết thúc bằng cách nói đi ra và lấy cho tôi một số dữ liệu.

+0

tôi nghĩ rằng nó phát hiện sự kết thúc của chuỗi: đó là nơi bạn không lấy lại đối tượng proxy tìm kiếm! – phoet

+0

Đây không phải là câu hỏi. Câu hỏi đặt ra là tại sao '' 'Product.first.title''' trả về' '' nil''' cho đến khi '' 'Product.first''' được gọi, khi' '' method_missing''' được sử dụng bên trong một mô hình. Khi bạn đã gọi '' 'Product.first''' title trả về' '' My sample blog'''. – user544941

+0

@ user544941: Ah, tôi thấy những gì anh ta hỏi về: cái gì thay thế hoặc bỏ qua 'phương thức_missing' của anh ta. –

Các vấn đề liên quan