Rails layouts ต่อการกระทำ?


165

ฉันใช้เลย์เอาต์ที่แตกต่างกันสำหรับการกระทำบางอย่าง (โดยส่วนใหญ่เป็นการกระทำใหม่ในคอนโทรลเลอร์ส่วนใหญ่)

ฉันสงสัยว่าวิธีที่ดีที่สุดในการระบุเค้าโครงจะเป็นอย่างไร (ฉันใช้เลย์เอาต์ 3 แบบหรือมากกว่าในคอนโทรลเลอร์เดียวกัน)

ฉันไม่ชอบการใช้

render: layout => 'name'

ฉันชอบทำ

เลย์เอาต์ 'ชื่อ',: only => [: ใหม่]

แต่ฉันไม่สามารถใช้สิ่งนั้นเพื่อระบุเค้าโครงที่แตกต่างกัน 2 รูปแบบขึ้นไป

ตัวอย่างเช่น:

เมื่อฉันเรียกเลย์เอาต์ 2 ครั้งในคอนโทรลเลอร์เดียวกันโดยมีชื่อเลย์เอาต์ที่แตกต่างกันและตัวเลือกที่แตกต่างกันเท่านั้นตัวแรกจะถูกละเว้น - การกระทำเหล่านั้นจะไม่แสดงในเค้าโครงที่ฉันระบุ

หมายเหตุ: ฉันใช้ Rails 2


1
เอกสารประกอบ Rails Guides: ไกด์. rubyonrails.org/ …
เควิน

1
จุดดี. เอกสารสำหรับ Rails 2: guide.rubyonrails.org/v2.3.11/…
Kevin

2
(นอกจากนี้ฉันโพสต์คำแนะนำเพื่อช่วยให้ผู้อ่านในอนาคตฉันไม่สงสัยเลยว่าคุณมีปัญหาของคุณแก้ไขเมื่อนานมาแล้ว ;-)
เควิน

คำตอบ:


297

คุณสามารถใช้วิธีการตั้งค่าเค้าโครง

class MyController < ApplicationController
  layout :resolve_layout

  # ...

  private

  def resolve_layout
    case action_name
    when "new", "create"
      "some_layout"
    when "index"
      "other_layout"
    else
      "application"
    end
  end
end

22
เจ๋งขอบคุณ และในกรณีที่มีคนต้องการทำสิ่งที่ง่ายขึ้นด้วยซับเดียวต่อไปนี้เป็นไปได้ มันอ่านง่ายและวางไว้ด้านบนของตัวควบคุม ---layout Proc.new{ ['index', 'new', 'create'].include?(action_name) ? 'some_layout' : 'other_layout' }
holli

1
สิ่งนี้จะมีผลกระทบอย่างมากต่อประสิทธิภาพการทำงานของแอปพลิเคชั่นหรือไม่หากเลย์เอาต์ต่างๆใช้ไฟล์ css & js ที่แตกต่างกันตามลำดับ
Noz

15
-1: ซับซ้อนเกินไป ความคิดเห็นด้านล่าง ( stackoverflow.com/a/21203783/285154 ) เป็นตัวเลือกที่ดีที่สุด
dimitarvp

ขอบคุณ! นี่ยังคงเป็นปัญหาใน Rails 4.2 บางทีถ้าคุณใช้การควบคุมสืบทอดในหลายระดับ ฉันเคยใช้วิธีการก่อนหน้านี้ แต่ไม่ได้คิดที่จะทดสอบว่าเมื่อฉันมีปัญหาตอนนี้ขอบคุณอีกครั้ง
244an

@dimitko ไม่มันไม่ใช่ฉันได้อ้างอิงถึงวิธีแก้ปัญหาในคำถามนั้นแล้ว มันไม่ทำงานถ้าคุณต้องการใช้เลย์เอาต์ 3 แบบหรือมากกว่า (ตามที่เป็นกรณีของฉัน)
mrbrdo

201

หากคุณเลือกระหว่างสองเลย์เอาท์เท่านั้นคุณสามารถใช้:only:

class ProductsController < ApplicationController
   layout "admin", only: [:new, :edit]
end

หรือ

class ProductsController < ApplicationController
   layout "application", only: [:index]
end

2
ด้วยปัญหานี้คือคุณไม่สามารถเข้าถึงวัตถุเช่น current_user เพื่อกำหนดรูปแบบตามเงื่อนไข
แอนดรูว์เค

@AndrewK การเลือกเลย์เอาต์แบบไดนามิกดูเหมือนจะไม่ได้เป็นส่วนหนึ่งของคำถามที่ถาม
Nick

11
หากคุณคนใดอ่านคำถามที่คุณจะรู้ว่านี่ไม่ใช่คำตอบที่ถูกต้องเพราะฉันได้อธิบายวิธีแก้ปัญหานี้ในคำถามแล้วและทำไมมันไม่ทำงานในกรณีของฉัน (3 เลย์เอาต์หรือมากกว่า)
mrbrdo

2
เช่นเดียวกับ mrbrdo กล่าวว่านี่ไม่ใช่คำตอบ คำถามของเขาบ่งบอกเป็น(I am using 3 or more different layouts in the same controller)พิเศษ คำตอบนี้อนุญาตเลย์เอาต์และไม่มีเลย์เอาต์ไม่แตกต่างกัน
Michael

49

คุณสามารถระบุเค้าโครงสำหรับแต่ละการกระทำโดยใช้respons_to :

  def foo
    @model = Bar.first
    respond_to do |format|
      format.html {render :layout => 'application'}
    end
  end

สำหรับฉันนี่คือคำตอบที่ยืดหยุ่นมากขึ้น การออกไปโดยใช้layout "[...]" to the controller class only allows one statement effectively. If you have more than two layouts to deal with (say, admin, generic_app, tailored_app), you will experience Render และ / หรือการเปลี่ยนเส้นทางถูกเรียกหลายครั้งในข้อผิดพลาดการกระทำนี้ และคุณไม่มีทางเลือกนอกจากใช้คำแนะนำนี้
เจอโรม

1
คำตอบนี้ดีที่สุดเรียบง่ายและเรียบร้อยซึ่งต่างจากการใช้เมธอดที่มีสวิตช์หรือคำสั่งด้านใน
kev

นอกจากนี้มันยังสามารถระบุไฟล์ erb และเลย์เอาต์ทั้งสองได้format.html { render 'custom_index', layout: 'application' } ในวิธีเดียวกัน
thatway_3

12

คุณยังสามารถระบุเค้าโครงสำหรับการดำเนินการโดยใช้การแสดงผล:

def foo
  render layout: "application"
end


7

วิธีต่างๆในการระบุเค้าโครงภายใต้คอนโทรลเลอร์:

  1. ในรหัสต่อไปนี้รูปแบบ application_1 ถูกเรียกภายใต้ดัชนีและแสดงการกระทำของตัวควบคุมผู้ใช้และรูปแบบแอปพลิเคชัน (เค้าโครงเริ่มต้น) จะถูกเรียกสำหรับการดำเนินการอื่น ๆ

    class UsersController < ApplicationController
      layout "application_1", only: [:index, :show]
    end
  2. ในรหัสต่อไปนี้รูปแบบ application_1 ถูกเรียกสำหรับการกระทำทั้งหมดของผู้ใช้ควบคุม

    class UsersController < ApplicationController
       layout "application_1"
    end
  3. ในรหัสต่อไปนี้รูปแบบ application_1 ถูกเรียกใช้สำหรับการทดสอบการกระทำของตัวควบคุมผู้ใช้เท่านั้นและสำหรับรูปแบบแอปพลิเคชันการกระทำอื่น ๆ (ค่าเริ่มต้น) เรียกว่า

        class UsersController < ApplicationController
          def test
            render layout: "application_1"
          end
        end

5

ความแม่นยำ:

วิธี DRY ที่ไม่ทำงาน แต่เป็นสิ่งที่คุณเห็นด้านบน แต่ด้วยความแม่นยำ: เลย์เอาต์ต้องอยู่หลังตัวแปรสำหรับการทำงาน ("@some") เช่น :

def your_action
   @some = foo
   render layout: "your_layout"
end

และไม่ :

def your_action
   render layout: "your_layout"
   @some = foo
   @foo = some
end

หากคุณทำ before_action ... มันจะไม่ทำงานเช่นกัน

หวังว่ามันจะช่วย

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.