Có bất kỳ chức năng Rails nào để kiểm tra xem một phần có tồn tại không?


98

Khi tôi hiển thị một phần không tồn tại, tôi nhận được Ngoại lệ. Tôi muốn kiểm tra xem một phần có tồn tại hay không trước khi hiển thị nó và trong trường hợp nó không tồn tại, tôi sẽ kết xuất thứ khác. Tôi đã thực hiện đoạn mã sau trong tệp .erb của mình, nhưng tôi nghĩ nên có cách tốt hơn để thực hiện việc này:

    <% begin %>
      <%= render :partial => "#{dynamic_partial}" %>
    <% rescue ActionView::MissingTemplate %>
      Can't show this data!
    <% end %>

1
Câu trả lời là sử dụng rescuelà rủi ro. Tôi sẽ xem xét các giải pháp khác trước khi sử dụng nó.
Grant Hutchins

Câu trả lời:


98

Hiện tại, tôi đang sử dụng phần sau trong các dự án Rails 3 / 3.1 của mình:

lookup_context.find_all('posts/_form').any?

Ưu điểm so với các giải pháp khác mà tôi đã thấy là điều này sẽ hiển thị trong tất cả các đường dẫn chế độ xem thay vì chỉ gốc đường ray của bạn. Điều này rất quan trọng đối với tôi vì tôi có rất nhiều động cơ đường ray.

Điều này cũng hoạt động trong Rails 4.


9
lookup_context.exists? ('posts / find') không phù hợp với tôi. Thay vào đó, tôi đã sử dụng lookup_context.exists? (Tên, tiền tố, một phần) hoặc lookup_content.exists? ('Find', 'posts', true) trong ví dụ này.
Jenn

2
Đây là cách hiện tại (rails> = 3.2) để kiểm tra các mẫu (nguồn apidock )
maček

1
Nếu một phần nằm trong cùng một thư mục với mẫu dạng xem hiện tại, bạn có thể sử dụng lookup_context.exists?("find", lookup_context.prefixes, true). Bằng cách này, bạn không cần phải mã hóa thư mục chế độ xem vào cuộc gọi. Lưu ý, đây là dành cho những người đi dự tiệc. Đối với những người không phân chia, hãy bỏ qua đối số cuối cùng (hoặc sử dụng sai thay vì đúng)
Nathan Wallace

71

Tôi cũng đang đấu tranh với điều này. Đây là phương pháp tôi đã sử dụng:

<%= render :partial => "#{dynamic_partial}" rescue nil %>

Về cơ bản, nếu một phần không tồn tại, không làm gì cả. Tuy nhiên, bạn có muốn in thứ gì đó nếu thiếu một phần không?

Chỉnh sửa 1: Ồ, tôi không đọc hiểu được. Bạn đã nói rằng bạn muốn hiển thị một cái gì đó khác. Trong trường hợp đó, làm thế nào về điều này?

<%= render :partial => "#{dynamic_partial}" rescue render :partial => 'partial_that_actually_exists' %>

hoặc là

<%= render :partial => "#{dynamic_partial}" rescue "Can't show this data!" %>

Chỉnh sửa 2:

Thay thế: Kiểm tra sự tồn tại của tệp một phần:

<%= render :partial => "#{dynamic_partial}" if File.exists?(Rails.root.join("app", "views", params[:controller], "_#{dynamic_partial}.html.erb")) %>

6
Câu hỏi của tôi là tôi không muốn sử dụng ngoại lệ để thực hiện kiểm soát dòng chảy, mà là một anti-pattern: stackoverflow.com/questions/1546514/...
Daniel Cukier

6
Ngoại lệ là một loại điều khiển luồng được sử dụng để xử lý những thứ xảy ra ngoài hoạt động bình thường của chương trình. Nếu phần động được cho là có ở đó nhưng có sự cố xảy ra và nó kết thúc không ở đó, thì đó là cách sử dụng hợp lý cho một trường hợp ngoại lệ (tất nhiên là IMO - việc sử dụng hợp lý các ngoại lệ chính là một cuộc thánh chiến). Tôi muốn nói cách thay thế của bạn là kiểm tra hệ thống tệp xem tệp thực sự có tồn tại hay không. Tôi sẽ cập nhật câu trả lời của mình với mã đó.
Jeff

3
Tôi thích giải pháp, tuy nhiên, nó nuốt chửng bất kỳ loại ngoại lệ nào được ném vào một phần. IMHO điều này làm cho việc theo dõi lỗi khó hơn.
Matt

5
Nếu bạn có một loại ngoại lệ khác, các phương thức rescue nil... rescue ...sẽ ẩn nó. Điều đó dẫn đến các lỗi rất khó gỡ lỗi.
nicholaides 23/12/11

8
Tôi thực sự không thích giải pháp này. giải cứu là tốn kém, và File.exist? giả định rằng một phần chỉ có thể ở một vị trí. Tôi tin rằng giải pháp của @ Rein bằng cách sử dụng lookup_context là cách tốt nhất.
Bert Goethals

52

Từ bên trong một chế độ xem, template_exists? hoạt động, nhưng quy ước gọi không hoạt động với chuỗi tên từng phần duy nhất, thay vào đó nó có template_exists? (tên, tiền tố, một phần)

Để kiểm tra một phần trên đường dẫn: app / views / posts / _form.html.slim

Sử dụng:

lookup_context.template_exists?("form", "posts", true)

Trên Rails 3.0.10, tôi thấy rằng nếu tôi có một tiện ích mở rộng thay thế, như app / views / posts / _foo.txt.erb, tôi cần thêm nó vào đối số là: template_exists? ("Foo.txt", "posts" , đúng)
Gabe Martin-Dempesy,

Tính năng này không được dùng nữa trong rails 3.2
thứ hai 11/12/12

Nó dường như không được ủy quyền trong Rails 3.2.x, tuy nhiên, đối số thứ hai là một mảng tiền tố. Hơn nữa, nó tồn tại trên bộ điều khiển hiện tại.
Brendan

2
Bạn có thể sử dụng lookup_context.prefixes làm đối số thứ hai: lookup_context.template_exists? ("Form", lookup_context.prefixes, true)
lion.vollnhals

Đây là câu trả lời tốt hơn về cách truy cập thông tin này từ lớp xem.
Brendon Muir

30

Trong Rails 3.2.13, nếu bạn đang ở trong bộ điều khiển, bạn có thể sử dụng điều này:

template_exists?("#{dynamic_partial}", _prefixes, true)

template_exists?được ủy quyền lookupcontext, như bạn có thể thấy trongAbstractController::ViewPaths

_prefixes đưa ra bối cảnh của chuỗi kế thừa của bộ điều khiển.

true bởi vì bạn đang tìm kiếm một phần (bạn có thể bỏ qua đối số này nếu bạn muốn một mẫu thông thường).

http://api.rubyonrails.org/classes/ActionView/LookupContext/ViewPaths.html#method-i-template_exists-3F


Đã ủng hộ. Cập nhật nhiều hơn và giải thích tốt hơn về các thông số.
jacobsimeon

4
Từ một cái nhìn (chẳng hạn như một bố cục), các công trình này: lookup_context.template_exists?("navbar", controller._prefixes, :partial). Điều này cho tôi biết liệu mẫu hiện tại đang hiển thị bố cục này có một phần "thanh điều hướng" đã nêu hay không và nếu có thì tôi có thể kết xuất nó. Tôi vượt qua :partialchỉ để nói rõ ràng về boolean đó là gì - :partiallà sự thật. Cảm ơn vì một _prefixeschút, @Flackou!
pdobb

Thay thế _prefixesbằng nilnếu bạn đang gọi một phần nằm trong thư mục mẹ khác.
ben

8

Tôi biết điều này đã được trả lời và đã có tuổi đời hàng triệu năm, nhưng đây là cách tôi kết thúc việc sửa lỗi này cho tôi ...

Đường ray 4.2

Đầu tiên, tôi đưa cái này vào application_helper.rb của mình

  def render_if_exists(path_to_partial)
    render path_to_partial if lookup_context.find_all(path_to_partial,[],true).any?
  end

và bây giờ thay vì gọi

<%= render "#{dynamic_path}" if lookup_context.find_all("#{dynamic_path}",[],true).any? %>

tôi chỉ gọi <%= render_if_exists "#{dynamic_path}" %>

hy vọng rằng sẽ giúp. (chưa thử trong rails3)


1
Điều này không hiệu quả nếu bạn muốn cung cấp dự phòng. Nó cũng không xem xét các biến cục bộ.
phillyslick

Điều này thật đúng với gì mà tôi đã tìm kiếm. Câu trả lời rất rõ ràng.
Nắng

1
@BenPolinsky Tôi cho rằng bạn có thể sử dụng def render_if_exists(*args); render(*args) if ...cho điều đó
trang web

6

Tôi đã sử dụng mô hình này nhiều lần với thành công lớn:

<%=
  begin
    render partial: "#{dynamic_partial}"
  rescue ActionView::MissingTemplate
    # handle the specific case of the partial being missing
  rescue
    # handle any other exception raised while rendering the partial
  end
%>

Lợi ích của đoạn mã trên là chúng tôi có thể xử lý các trường hợp cụ thể:

  • Một phần thực sự bị thiếu
  • Một phần tồn tại, nhưng nó đã gây ra lỗi vì một số lý do

Nếu chúng ta chỉ sử dụng mã <%= render :partial => "#{dynamic_partial}" rescue nil %>hoặc một số dẫn xuất, một phần có thể tồn tại nhưng tạo ra một ngoại lệ sẽ bị ăn mòn một cách âm thầm và trở thành một nguồn đau đớn để gỡ lỗi.


4

Điều gì về người trợ giúp của riêng bạn:

def render_if_exists(path, *args)
  render path, *args
rescue ActionView::MissingTemplate
  nil
end
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.