2012-05-06 23 views
19

Tôi muốn sử dụng những người trợ giúp quen thuộc của đường ray, nhưng có chức năng thay đổi một chút. Con đường tôi nhìn thấy nó, tôi muốn để có thể làm điều gì đó như:Ghi đè người giúp đỡ đường ray với quyền truy cập vào số

module AwesomeHelper 
    #... create alias of stylesheet_link_tag to old_stylesheet_link_tag 
    def stylesheet_link_tag(*args) 
    if @be_awesome 
     awesome_stylesheet_link_tag *args 
    else 
     old_stylesheet_link_tag *args 
    end 
    end 
end 

Con đường tôi nhìn thấy nó, tôi có ba lựa chọn:

  1. khỉ vá: Mở lại các module ray helper . Nếu đội đường ray bao giờ thay đổi tên của mô-đun trợ giúp của họ, mã của tôi trở thành một nguồn của sự giòn. Không thể vượt qua, nhưng không lý tưởng.
  2. Sử dụng các tên phương thức khác nhau: Cố gắng bám vào giao diện đường ray chung có thể là sự sụp đổ của tôi. Những thay đổi của tôi có thể trở thành một nguồn gây nhầm lẫn cho các nhà phát triển khác
  3. Phương pháp tách (mới): Không chắc chắn điều này có hiệu quả hay không hoặc sẽ có những hạn chế tương tự như 1. Sẽ nghiên cứu điều này, nhưng điều này có thể là tốt điểm khởi đầu.

Vì vậy, câu hỏi ở đây là, tôi có bị mắc kẹt với một trong các giải pháp phụ tối ưu này không, hoặc có cách nào khác mà tôi chưa xem xét không? Nếu tôi đi cho tùy chọn 3, có cách nào để làm điều đó mà không trực tiếp giải quyết các mô-đun trợ giúp đường ray?

(Lưu ý:. Tôi đã gỡ bỏ bối cảnh, vì nó cho biết thêm gì cho câu hỏi)

Trả lời

30

Có cách tốt hơn so với bất kỳ tùy chọn nào được liệt kê của bạn. Chỉ cần sử dụng super:

module AwesomeHelper 
    def stylesheet_link_tag(*sources) 
    if @be_awesome 
     awesome_stylesheet_link_tag *sources 
    else 
     super 
    end 
    end 
end 

Trọng stylesheet_link_tag trong AwesomeHelper sẽ đảm bảo rằng, khi stylesheet_link_tag được gọi, Ruby sẽ gặp nó trong đường dẫn phương pháp tra cứu trước khi nó chạm ActionView::Helpers::AssetTagHelper. Nếu @be_awesometrue, bạn có thể chịu trách nhiệm và dừng mọi thứ ngay tại đó và nếu không, cuộc gọi tới super mà không có dấu ngoặc đơn sẽ chuyển một cách minh bạch tất cả các đối số lên đến triển khai Rails. Bằng cách này, bạn không phải lo lắng về đội ngũ nhân viên Rails đang di chuyển mọi thứ xung quanh bạn!

+0

Bạn biết những gì ... điều đó thật điên rồ, tôi đang cố gắng đánh giá trí não của mình để giải thích tại sao Tôi nghĩ nó sẽ không hoạt động! Tôi sẽ thử nó tối nay, và nếu nó hoạt động, tôi sẽ có những từ nghiêm trọng với bộ não của tôi, có lẽ liên quan đến một bức tường gạch. Sau khi, tất nhiên, chấp nhận câu trả lời của bạn ...: D – user208769

+1

@ user208769 Hehehe. Thật tuyệt vời. Tốt nhất là tôi hiểu, các phương pháp ghi đè theo cách này thường thích hợp hơn trong mọi trường hợp. [Class # tổ tiên] (http://ruby-doc.org/core-1.9.3/Module.html#method-i-ancestors) có thể thực sự hữu ích trong việc tìm ra một vị trí tốt trong đường dẫn phương pháp tra cứu để tấn công phương pháp gửi đi (hoặc nơi mô-đun tùy chỉnh của bạn có ghi đè cần được đưa vào hiệu quả tốt nhất). – Cade

+0

Cái gì? :) Bạn phải đùa! Đây là một hình ảnh khổng lồ! Theo cách của bạn, bạn phải bao gồm bạn helper trong MỌI lớp bao gồm AssetTagHelper. Thời gian trôi qua và bạn hoặc người khác có thể quên mất việc cần bao gồm bản vá của bạn. Bạn chỉ cần bao gồm AssetTagHelper và bắt đầu tự hỏi: tại sao trang web của tôi bây giờ trông khác nhau? Thật tốt khi bạn và người tạo bản vá là cùng một người. Nhưng nếu không thì sao? – jdoe

6

tôi không sử dụng đá quý này, vì vậy tôi sẽ trả lời bạn trong một cách chung chung hơn.

Giả sử bạn muốn ghi nhật ký cuộc gọi đến link_to trợ giúp (vâng, ví dụ giả tạo, nhưng hiển thị ý tưởng). Tìm kiếm API cung cấp cho bạn hiểu rằng link_to nằm bên trong mô-đun ActionView::Helpers::UrlHelper. Vì vậy, bạn tạo ra một số tập tin trong bạn, nói, config/initializers thư mục với các nội dung sau:

# like in config/initializers/link_to_log.rb 
module ActionView::Helpers::UrlHelper 

    def link_to_with_log(*args, &block) 
     logger.info '**** LINK_TO CALL ***' 
     link_to_without_log(*args, &block) # calling the original helper 
    end 

    alias_method_chain :link_to, :log 
end 

Cốt lõi của chức năng này - alias_method_chain (có thể nhấp). Sử dụng nó SAU KHI xác định phương thức xxx_with_feature.

+0

Yeah, phương pháp này là những gì tôi có nghĩa là bởi "khỉ vá đường ray cụ module" - mà hoạt động tốt, nhưng nếu đường ray lõi thay đổi tên mô-đun của họ, phá vỡ mã của tôi. Đây có thể không phải là một vấn đề lớn, nhưng tôi tò mò muốn xem liệu có những giải pháp nào khác không. Điều đó nói rằng, đã quên về alias_method_chain, cảm ơn bạn đã nhắc tôi về điều đó! – user208769

+0

P.S: Đã cập nhật câu hỏi để xóa ví dụ đá quý. Hy vọng rằng bố cục này ít gây nhầm lẫn! Cảm ơn bạn. – user208769

+0

Rủi ro luôn ở đó! Nếu bạn lo lắng về 'alias_method_chain' thì bạn không nên: nó tồn tại kể từ phiên bản 1.4.0 (năm 2007). Nếu bạn lo lắng về các phần khác của chương trình của bạn sau đó đảm bảo kiểm tra phong nha bảo hiểm. – jdoe

2

Tôi thực sự khuyến khích bạn xem xét tùy chọn # 2, ghi đè hành vi của các phương thức đường ray theo cách rõ ràng đối với người gọi.

Phương pháp mới của bạn nên được gọi là awesome_stylesheet_link_tag để những người phát triển Rails khác có thể đọc mã của bạn và đặt câu hỏi "Điều gì thật tuyệt vời về thẻ liên kết?".

Là một thay đổi nhỏ hơn, bạn có thể thực hiện ghi đè nhưng vượt qua trong :awesome => true làm đối số để ít nhất họ có một đầu mối cho thấy có điều gì đó đang diễn ra.

Thay đổi hành vi của một phương pháp được sử dụng rộng rãi như stylesheet_link_tag tạo ra một sự hiểu lầm tiềm ẩn trong tương lai khi không cần thiết.

+0

Cảm ơn bạn đã nhập. Trong khi bình thường tôi đồng ý, trong trường hợp cụ thể này tôi nghĩ sự nhất quán là hợp lý - tôi đang làm điều này để sử dụng wicked_pdf và có chính xác cùng một mã tạo ra một PDF hoặc một trang web. Mặc dù wicked_pdf theo mặc định thực hiện như bạn nói (wicked_pdf_stylesheet_link_tag), nó đòi hỏi quá nhiều lần lặp lại đối với tôi và tôi cho rằng có thể chấp nhận rằng chức năng có thể thay đổi nếu bạn đang tạo tệp PDF. Nhưng bạn làm cho một điểm tốt, và một số lời khuyên hữu ích, vì vậy cảm ơn bạn. – user208769

4

Hãy thử sử dụng alias_method:

module AwesomeHelper 
    alias_method :original_stylesheet_link_tag, :stylesheet_link_tag 

    def stylesheet_link_tag(*sources) 
    if @be_awesome 
     awesome_stylesheet_link_tag *sources 
    else 
     original_stylesheet_link_tag *sources 
    end 
    end 
end