ฉันจะแสดงผลบางส่วนของรูปแบบอื่นใน Rails ได้อย่างไร


115

ฉันกำลังพยายามสร้างการตอบสนอง JSON ที่มี HTML บางส่วน ดังนั้นฉันมี/app/views/foo/bar.json.erb:

{
  someKey: 'some value',
  someHTML: "<%= h render(:partial => '/foo/baz') -%>"
}

ฉันต้องการที่จะทำให้แต่มันจะทำให้/app/views/foo/_baz.html.erb /app/views/foo/_baz.json.erbการผ่าน:format => 'html'ไม่ช่วย


หัวข้อคำถามนั้นกว้างกว่าปัญหาเฉพาะของเจมส์มาก หากคุณกำลังมองหาโซลูชันอื่น ๆ โปรดดูที่นี่: stackoverflow.com/questions/7616097/…
miguelsan

คำตอบ:


101

เริ่มต้นด้วย Rails 3.2.3 เมื่อเรียกการเรนเดอร์: บางส่วน (ใช้ได้เฉพาะนอกrespond_toบล็อก)

render formats: [ :html ]

แทน

render format: 'html'

ฉันเดาว่าอาจมีคำตอบที่ "ดีที่สุด" ที่แตกต่างกันขึ้นอยู่กับบริบทดังนั้นจึงยากที่จะเพิ่มคะแนนให้กับคำถามนี้อย่างมีความหมาย แต่สิ่งนี้เติมเต็มความต้องการของฉันในการแสดงเทมเพลต HTML จากภายใน RJS ซึ่งเป็นชื่อเดียวกันหลังจากที่หวังว่า:formatตัวเลือกจะ งาน. ขอบคุณ!
ches

1
นอกจากนี้ยังใช้ได้กับ Rails 5.0.2 อย่างไรก็ตามทราบว่าคุณอาจต้องระบุ:content_typeตัวเลือกในบางกรณี - เช่นการแสดงผล HTML แม่แบบจากภายในบล็อกสามารถทำได้ด้วยformat.pdf render "template", formats: [:html], content_type: "text/html"ฉันต้องการสิ่งนี้เพราะฉันอนุญาตให้ดาวน์โหลดตัวอย่างหนังสือของฉันได้โดยตรงสำหรับสมาชิกในรายชื่ออีเมลของฉันเท่านั้น - ผู้เยี่ยมชมทั่วไปจะได้รับแบบฟอร์มลงทะเบียนแทน
Michael Trojanek

64

เกิดอะไรขึ้น

render :partial => '/foo/baz.html.erb'

? ฉันเพิ่งลองทำสิ่งนี้เพื่อแสดง HTML ERB บางส่วนจากภายในเทมเพลต Atom builder และมันก็ใช้ได้ดี ไม่ต้องวุ่นวายกับตัวแปรส่วนกลาง (ใช่ฉันรู้ว่ามี "@" อยู่ข้างหน้า แต่นั่นคือสิ่งที่เป็น)

แม้ว่าwith_format &blockแนวทางของคุณจะยอดเยี่ยมและมีข้อได้เปรียบที่คุณระบุรูปแบบเท่านั้นในขณะที่วิธีการง่ายๆระบุเครื่องมือเทมเพลต (ERB / ​​builder / etc) ด้วย


26
ข้อเสียเพียงประการเดียวคือหากบางส่วนของคุณแสดงผลบางส่วนอื่น ๆ จะล้มเหลวเว้นแต่คุณจะเข้าไปและเปลี่ยนการเรียกใช้บางส่วนที่แสดงผลทั้งหมดเพื่อรวม ".html.erb" ไว้ในชื่อ
chrisrbailey

4
คุณไม่จำเป็นต้องระบุเครื่องมือสร้างเทมเพลตเพื่อให้สิ่งนี้ทำงานได้ (อย่างน้อยที่สุดเท่าราง 3). ต่อไปนี้ใช้ได้ดี: render (: partial => "baz.html")
Tim Harper

1
ไม่ทำงานถ้าคุณมี partials ที่แตกต่างกันสำหรับสถานที่ที่แตกต่างกัน (เช่นbaz.en.html.erb, baz.fr.html.erb) และคุณต้องการrender :partialตรรกะในการเลือกหนึ่งที่เหมาะสม (กับ fallbacks ฯลฯ )
John

1
สำหรับราง 3.2.3 ฉันเห็นคำเตือนต่อไปนี้เมื่อใช้โซลูชันนี้:DEPRECATION WARNING: Passing a template handler in the template name is deprecated. You can simply remove the handler name or pass render :handlers => [:erb] instead.
YWCA สวัสดี

3
หนึ่งในข้อเสียของวิธีนี้คือการแปลเป็นภาษาจะมองหาแทนfoo.baz.html.[your_string] foo.baz.[your_string]คำตอบของ zgchurc เป็นทางออกที่ดีกว่า
mbillard

32

สำหรับ Rails 3 บล็อก with_format ใช้งานได้ แต่แตกต่างกันเล็กน้อย:

  def with_format(format, &block)
    old_formats = formats
    self.formats = [format]
    block.call
    self.formats = old_formats
    nil
  end

ใช้งานได้กับราง 3.2.0 ด้วย :)
gucki

32

Rails 4 จะอนุญาตให้คุณส่งพารามิเตอร์รูปแบบ ดังนั้นคุณสามารถทำได้

render(:partial => 'form', :formats => [:html])} 

โปรดทราบว่าคุณสามารถทำสิ่งที่คล้ายกันใน Rails 3 แต่จะไม่ส่งรูปแบบนั้นไปยังส่วนย่อยใด ๆ (หากแบบฟอร์มเรียกใช้ส่วนอื่น ๆ )

คุณสามารถมีความสามารถ Rails 4 ใน Rails 3 โดยการสร้าง config / initializers / renderer.rb:

class ActionView::PartialRenderer
  private
  def setup_with_formats(context, options, block)
    formats = Array(options[:formats])
    @lookup_context.formats = formats | @lookup_context.formats
    setup_without_formats(context, options, block)
  end

  alias_method_chain :setup, :formats
end

ดูhttp://railsguides.net/2012/08/29/rails3-does-not-render-partial-for-specific-format/


แปลกฉันสงสัยว่าทำไมแอป Rails 3.2.19 ถึงไม่ทำงานฉันสงสัยว่าอะไรทำให้แอปของฉันแตกต่าง ไม่สามารถรับการเรนเดอร์ ActionView: บางส่วนเพื่อเคารพ: รูปแบบ arg ดูเหมือนว่าจะไม่สร้างความแตกต่างเลยแม้แต่กับแพตช์นี้
jrochkind

29

จากการตอบสนองของ roninekฉันพบทางออกที่ดีที่สุดดังต่อไปนี้:

ใน /app/helpers/application.rb:

def with_format(format, &block)
  old_format = @template_format
  @template_format = format
  result = block.call
  @template_format = old_format
  return result
end

ใน /app/views/foo/bar.json:

<% with_format('html') do %>
  <%= h render(:partial => '/foo/baz') %>
<% end %>

ทางเลือกอื่นคือการกำหนดค่าใหม่renderเพื่อยอมรับ:formatพารามิเตอร์

ฉันไม่render :fileสามารถทำงานกับคนในพื้นที่และไม่มีความกระตือรือร้นในเส้นทาง


8
แฮ็คเกินไปสำหรับรสนิยมของฉัน ดีกว่าที่จะระบุส่วนขยายทั้งหมด
Tim Harper

1
สำหรับราง 3 ดูคำตอบของ zgchurch
lillq

25

ใน Rails 3 มุมมองมีอาร์เรย์รูปแบบซึ่งหมายความว่าคุณสามารถตั้งค่าให้มองหา [: mobile,: html] การตั้งค่าที่จะเริ่มต้นเพื่อค้นหา: เทมเพลตมือถือ แต่กลับไปที่: เทมเพลต html ผลของการตั้งค่านี้จะลดหลั่นลงไปในบางส่วนด้านใน

วิธีที่ดีที่สุด แต่ยังมีข้อบกพร่องที่ฉันสามารถตั้งค่าได้คือวางบรรทัดนี้ไว้ที่ด้านบนของเทมเพลตมือถือแบบเต็มแต่ละแบบ (แต่ไม่ใช่บางส่วน)

<% self.formats = [:mobile, :html] %>

ข้อบกพร่องคือคุณต้องเพิ่มบรรทัดนั้นในหลายเทมเพลต หากใครรู้วิธีตั้งค่าครั้งนี้จาก application_controller.rb ฉันก็อยากรู้ น่าเสียดายที่การเพิ่มบรรทัดนั้นลงในเลย์เอาต์มือถือของคุณไม่ได้ผลเนื่องจากเทมเพลตจะแสดงผลก่อนเค้าโครง


ขอขอบคุณที่อธิบายเรื่องนี้ ฉันลงเอยด้วยการใช้ที่อื่น: stackoverflow.com/questions/47459724/…
Joshua Pinter

16

เพียงแค่อธิบายสิ่งที่ zgchurch เขียน:

  • โดยคำนึงถึงข้อยกเว้น
  • ส่งคืนผลลัพธ์ของบล็อกที่เรียกว่า

คิดว่ามันอาจมีประโยชน์

def with_format(format, &block)
  old_formats = formats
  begin
    self.formats = [format]
    return block.call
  ensure
    self.formats = old_formats
  end
end

10

คุณมีสองทางเลือก:

1) ใช้ render :file

render :file => "foo/_baz.json.erb"

2) เปลี่ยนรูปแบบเทมเพลตเป็น html โดยตั้งค่าตัวแปร @template_format

<% @template_format = "html" %>
<%= h render(:partial => '/foo/baz') %>

1
<% @template_format = "html"%> ใช้ได้ผลสำหรับฉันเนื่องจากบางส่วนของฉันโหลดบางส่วนอื่น ๆ ฉันจึงไม่ต้องอัปเดตการแสดงผลอื่น ๆ ในเครือข่าย
pagetribe

5

ฉันมีไฟล์ชื่อ 'api / item.rabl' และฉันต้องการแสดงผลจากมุมมอง HTML ดังนั้นฉันจึงต้องใช้:

render file: 'api/item', formats: [:json]

( fileเนื่องจากไฟล์ไม่มีขีดล่างในชื่อformatsและไม่มีformat(และส่งผ่านและอาร์เรย์))


2

ดูเหมือนว่าการส่งformatsตัวเลือกจะแสดงผลอย่างถูกต้องใน Rails เวอร์ชันใหม่อย่างน้อย 3.2:

{
  someKey: 'some value',
  someHTML: "<%= h render('baz', formats: :html) -%>"
}

1

ฉันเจอเธรดนี้เมื่อฉันพยายามแสดง XML บางส่วนในไฟล์มุมมอง xml.builder อื่น ต่อไปนี้เป็นวิธีที่ดีที่จะทำ

xml.items :type => "array" do
    @items.each do |item|
        xml << render(:partial => 'shared/partial.xml.builder', :locals => { :item => item })
    end
end

และใช่ ... ชื่อไฟล์เต็มก็ใช้ได้เช่นกัน ...


ปัญหานี้เกิดจากปัญหาภายในเดียวกันกับที่ @chrisrbailey พูดถึงในคำตอบอื่น: หากบางส่วนที่คุณเรียกด้วยชื่อไฟล์แบบเต็มนั้นใช้บางส่วน (โดยไม่ระบุชื่อไฟล์เต็มสำหรับแต่ละไฟล์) จะล้มเหลว
James A. Rosen
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.