Apakah ada fungsi Rails untuk memeriksa apakah ada parsial?

98

Ketika saya membuat sebagian yang tidak ada, saya mendapatkan Pengecualian. Saya ingin memeriksa apakah ada parsial sebelum merendernya dan jika tidak ada, saya akan merender yang lain. Saya melakukan kode berikut di file .erb saya, tetapi saya pikir seharusnya ada cara yang lebih baik untuk melakukan ini:

    <% begin %>
      <%= render :partial => "#{dynamic_partial}" %>
    <% rescue ActionView::MissingTemplate %>
      Can't show this data!
    <% end %>
Daniel Cukier
sumber
1
Jawaban yang digunakan rescueberisiko. Saya akan melihat solusi lain sebelum menggunakannya.
Grant Hutchins

Jawaban:

98

Saat ini, saya menggunakan yang berikut ini di proyek Rails 3 / 3.1 saya:

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

Keuntungan dari solusi lain yang pernah saya lihat adalah ini akan terlihat di semua jalur tampilan, bukan hanya root rel Anda. Ini penting bagi saya karena saya memiliki banyak mesin rel.

Ini juga berfungsi di Rails 4.

Kendali
sumber
9
lookup_context.exists? ('posts / find') tidak berfungsi untuk saya. Sebagai gantinya saya menggunakan lookup_context.exists? (Name, prefix, partial) atau lookup_content.exists? ('Find', 'posts', true) dalam contoh ini.
Jenn
2
Ini adalah cara saat ini (rel> = 3.2) untuk memeriksa templat (sumber apidock )
maček
1
Jika parsial berada dalam folder yang sama dengan template tampilan saat ini, Anda dapat menggunakan lookup_context.exists?("find", lookup_context.prefixes, true). Dengan cara ini, Anda tidak perlu melakukan hard-code direktori view ke dalam panggilan. Perhatikan, ini untuk sebagian. Untuk non-parsial, hilangkan argumen terakhir (atau gunakan false, bukan true)
Nathan Wallace
71

Saya juga berjuang dengan ini. Ini adalah metode yang akhirnya saya gunakan:

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

Pada dasarnya, jika parsial tidak ada, jangan lakukan apa-apa. Apakah Anda ingin mencetak sesuatu jika parsial hilang?

Sunting 1: Oh, saya gagal dalam membaca pemahaman. Anda mengatakan bahwa Anda ingin merender sesuatu yang lain. Kalau begitu, bagaimana dengan ini?

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

atau

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

Edit 2:

Alternatif: Memeriksa keberadaan file parsial:

<%= render :partial => "#{dynamic_partial}" if File.exists?(Rails.root.join("app", "views", params[:controller], "_#{dynamic_partial}.html.erb")) %>
Jeff
sumber
6
Pertanyaan saya adalah saya tidak ingin menggunakan Pengecualian untuk melakukan kontrol aliran, yang merupakan anti-pola: stackoverflow.com/questions/1546514/…
Daniel Cukier
6
Pengecualian adalah jenis kontrol aliran yang digunakan untuk menangani hal-hal yang terjadi di luar operasi normal program. Jika dynamic parsial seharusnya ada tetapi ada yang tidak beres dan akhirnya tidak ada, maka itu adalah penggunaan yang wajar untuk pengecualian (IMO, tentu saja - penggunaan pengecualian yang tepat adalah perang suci itu sendiri). Saya akan mengatakan alternatif Anda adalah memeriksa sistem file untuk apakah file sebenarnya ada atau tidak. Saya akan memperbarui jawaban saya dengan kode itu.
Jeff
3
Saya suka solusinya, namun itu menelan segala jenis pengecualian yang dilemparkan secara parsial. IMHO ini membuat lebih sulit untuk melacak kesalahan.
Matt
5
Jika Anda memiliki jenis pengecualian yang berbeda, metode rescue nildan ... rescue ...akan menyembunyikannya. Itu mengarah ke bug yang sulit di-debug.
nicholaides
8
Saya sangat tidak menyukai solusi ini. menyelamatkan itu mahal, dan File.exists? mengasumsikan bahwa parsial hanya dapat berada di satu lokasi. @ Solusi Rein menggunakan lookup_context adalah cara untuk pergi saya percaya.
Bert Goethals
52

Dari dalam tampilan, template_exists? berfungsi, tetapi konvensi pemanggilan tidak berfungsi dengan string nama parsial tunggal, melainkan dibutuhkan template_exists? (nama, awalan, parsial)

Untuk memeriksa parsial di jalur: app / views / posts / _form.html.slim

Menggunakan:

lookup_context.template_exists?("form", "posts", true)
Luke Imhoff
sumber
Di Rails 3.0.10 saya menemukan bahwa jika saya memiliki ekstensi alternatif, seperti app / views / posts / _foo.txt.erb, saya perlu menambahkannya ke argumen sebagai: template_exists? ("Foo.txt", "posts" , benar)
Gabe Martin-Dempesy
Ini dihentikan di rel 3.2
maček
Tampaknya tidak didelegasikan di Rails 3.2.x, namun, argumen kedua adalah larik prefiks. Selanjutnya, itu ada pada pengontrol saat ini.
Brendan
2
Anda dapat menggunakan lookup_context.prefixes sebagai argumen kedua: lookup_context.template_exists? ("Form", lookup_context.prefixes, true)
lion.vollnhals
Ini adalah jawaban yang lebih baik dalam hal mengakses informasi ini dari lapisan tampilan.
Brendon Muir
30

Di Rails 3.2.13, jika Anda menggunakan pengontrol, Anda dapat menggunakan ini:

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

template_exists?didelegasikan ke lookupcontext, seperti yang Anda lihat diAbstractController::ViewPaths

_prefixes memberikan konteks rantai pewarisan pengontrol.

true karena Anda sedang mencari sebagian (Anda dapat menghilangkan argumen ini jika Anda menginginkan templat biasa).

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

Flackou
sumber
Suara positif. Penjelasan parameter yang lebih mutakhir dan lebih baik.
jacobsimeon
4
Dari pandangan (seperti layout), karya ini: lookup_context.template_exists?("navbar", controller._prefixes, :partial). Ini memberi tahu saya jika template saat ini yang merender tata letak ini memiliki sebagian "navbar" yang dinyatakan, dan jika demikian saya dapat merendernya. Saya lulus :partialhanya untuk secara eksplisit tentang apa itu boolean - :partialitu benar. Terima kasih untuk _prefixesbitnya, @Flackou!
pdobb
Ganti _prefixesdengan niljika Anda memanggil parsial yang ada di direktori induk yang berbeda.
ben
8

Saya tahu ini telah dijawab dan berusia satu juta tahun, tetapi inilah cara saya akhirnya memperbaikinya untuk saya ...

Rel 4.2

Pertama, saya taruh ini di application_helper.rb saya

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

dan sekarang alih-alih menelepon

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

saya baru saja menelepon <%= render_if_exists "#{dynamic_path}" %>

semoga membantu. (belum mencoba di rails3)

afxjzs
sumber
1
Ini tidak berfungsi jika Anda ingin memberikan fallback. Itu juga tidak memperhitungkan variabel lokal.
phillyslick
Inilah yang saya cari. Jawaban yang sangat bersih.
Cerah
1
@BenPolinsky Saya kira Anda dapat menggunakan def render_if_exists(*args); render(*args) if ...untuk itu
situs
6

Saya telah menggunakan paradigma ini dalam banyak kesempatan dengan sukses besar:

<%=
  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
%>

Manfaat kode di atas adalah kita dapat menangani dua kasus tertentu:

  • Parsial memang hilang
  • Parsial ada, tetapi itu membuat kesalahan karena beberapa alasan

Jika kita hanya menggunakan kode <%= render :partial => "#{dynamic_partial}" rescue nil %>atau beberapa turunan, parsial mungkin ada tetapi memunculkan pengecualian yang akan dimakan secara diam-diam dan menjadi sumber kesulitan untuk di-debug.

br3nt
sumber
4

Bagaimana dengan penolong Anda sendiri:

def render_if_exists(path, *args)
  render path, *args
rescue ActionView::MissingTemplate
  nil
end
Andrey
sumber