Rails: เรียกการทำงานของคอนโทรลเลอร์อื่นจากคอนโทรลเลอร์


118

ฉันต้องการเรียกการดำเนินการสร้างในคอนโทรลเลอร์ A จากคอนโทรลเลอร์ B

เหตุผลก็คือฉันต้องเปลี่ยนเส้นทางที่แตกต่างออกไปเมื่อฉันโทรจากคอนโทรลเลอร์ B

สามารถทำได้ใน Rails หรือไม่?



คุณกำลังพูดเกี่ยวกับ POST หรือ GET action? หาก GET คุณสามารถเปลี่ยนเส้นทางไปยังการกระทำนั้นได้ แต่เหตุผลนั้นไม่เงียบอย่างชัดเจนเนื่องจากคุณสามารถเปลี่ยนเส้นทางจากคอนโทรลเลอร์ A ไปยัง URL ใดก็ได้ที่คุณต้องการ
Voldy

คำตอบ:


64

คุณสามารถใช้การเปลี่ยนเส้นทางไปยังการกระทำนั้น:

redirect_to your_controller_action_url

เพิ่มเติมเกี่ยวกับ: Rails Guide

ในการแสดงผลการกระทำใหม่:

redirect_to your_controller_action_url and return

5
ฉันขอโทษ แต่คุณบอกได้ไหมว่าบรรทัดแรกและบรรทัดที่สองแตกต่างกันอย่างไร ฉันคิดว่าก่อนอื่นจะดำเนินการบรรทัดที่เหลือของรหัสแล้วเปลี่ยนเส้นทาง ถูกต้องหรือไม่
aks

ฉันคิดว่าอาจจะเป็นตัวอย่างสุดท้ายเป็นพิมพ์ผิดและควรจะแทนrender redirect_toคุณพูดอะไร @Spyros?
Magne

1
สวัสดี @spyros redirect_toไม่อนุญาตให้ใช้post: :methodและสิ่งนี้จะมีประโยชน์โดยเฉพาะอย่างยิ่งในการเปลี่ยนเส้นทางไปยังการcreateกระทำที่มีอยู่แล้วของคอนโทรลเลอร์อื่นตามที่ @ddayan ถามในครั้งแรก ฉันมีสถานการณ์ที่คล้ายกันซึ่งในบางสถานการณ์ฉันควรสร้างวัตถุอื่น เรียกอีกอย่างcreateได้ว่า DRYer ..
SanjiBukai

53

หากต้องการใช้คอนโทรลเลอร์ตัวหนึ่งจากอีกตัวให้ทำสิ่งนี้:

def action_that_calls_one_from_another_controller
  controller_you_want = ControllerYouWant.new
  controller_you_want.request = request
  controller_you_want.response = response
  controller_you_want.action_you_want
end

18
หากคุณต้องการให้การโทรกลับยังดำเนินการอยู่controller_you_wantคุณจะทำcontroller_you_want.process(:action_you_want)
Constantijn Schepens

3
ขอบคุณ! สิ่งนี้มีประโยชน์มากสำหรับสถานการณ์ที่คุณไม่ต้องการเปลี่ยนเส้นทางคุณเพียงแค่ต้องการวิธีแก้ปัญหาอย่างรวดเร็วเพื่อนำการดำเนินการจากคอนโทรลเลอร์หนึ่งไปใช้อีกตัวหนึ่ง การเปลี่ยนเส้นทางเป็นสิ่งที่แตกต่างจริงๆ นอกจากนี้: render status: :ok, json: JSON.parse(controller.render(:action_you_want).first)ดูเหมือนว่าจะทำงานเพื่อส่งคืน JSON จากคอนโทรลเลอร์อื่น
Yourpalal

1
คำตอบที่ดีคือสิ่งที่ฉันกำลังมองหา คำถามหนึ่ง - รูปแบบใดที่จะต้องใช้พารามิเตอร์ที่นี่? ฉันถือว่าพวกเขาอาศัยอยู่controller_you_want.requestแต่ไม่สามารถทำให้การยิงนี้ผ่านอินสแตนซ์แฮชหรือพารามิเตอร์ได้
SRack

ฉันไม่แน่ใจว่าคุณกำลังถามอะไร @SRack paramsเป็นที่สามารถใช้ได้controller_you_wantโดยการตั้งค่าrequestในบรรทัดที่ 3 นั่นคือสิ่งที่คุณถาม?
Sammy Larbi

1
ลองในราง 5 สำหรับการแสดงผลมันควรจะเป็นrender html: controller_you_want.process(:action_you_want)
นาซาร์คูลิเยฟ

41

ตรรกะที่คุณนำเสนอไม่ใช่ MVC ไม่ใช่ Rails เข้ากันได้

  • ตัวควบคุมแสดงมุมมองหรือเปลี่ยนเส้นทาง

  • วิธีการรันโค้ด

จากการพิจารณาเหล่านี้ฉันแนะนำให้คุณสร้างวิธีการในคอนโทรลเลอร์ของคุณและเรียกใช้จากการกระทำของคุณ

ตัวอย่าง:

 def index
   get_variable
 end

 private

 def get_variable
   @var = Var.all
 end

ที่กล่าวว่าคุณสามารถทำได้เหมือนกันทุกประการผ่านคอนโทรลเลอร์ที่แตกต่างกันและเรียกใช้วิธีการจากคอนโทรลเลอร์ A ในขณะที่คุณอยู่ในคอนโทรลเลอร์ B

คำศัพท์มีความสำคัญมากนั่นคือเหตุผลที่ฉันยืนยันมาก


ฉันรู้ว่าฉันไม่ควรทำเช่นนั้น แต่นี่ไม่ใช่ส่วนหนึ่งของแอปพลิเคชันของฉันมันเป็นเพียงการทดสอบและประเมินแอปพลิเคชันของฉัน
ddayan

9
รักมัน .. แยกเมธอดออกจากการเรนเดอร์แล้วเรียกแต่ละเมธอดตามต้องการ แค่คำถามเดียว .. get_variableตอนนี้จะเรียกจากคอนโทรลเลอร์อื่นได้อย่างไร?
FloatingRock

1
@FloatingRock เพิ่งสังเกตเห็นคำถาม / ความคิดเห็นของคุณ: คุณมีหลายทางเลือก: สามารถกำหนดได้ในบรรพบุรุษร่วมกันหรือคุณอาจรวม mixin ทั่วไป
หยุด

ชอบคำตอบไม่แน่ใจเกี่ยวกับส่วนของประโยคต่อท้าย
เจอราร์ดซิมป์สัน

30

คุณสามารถใช้url_forเพื่อรับ URL สำหรับคอนโทรลเลอร์และการดำเนินการจากนั้นใช้redirect_toเพื่อไปที่ URL นั้น

redirect_to url_for(:controller => :controller_name, :action => :action_name)

1
อีกอันดูเหมือนจะไม่ได้ผลสำหรับฉันสิ่งนี้ดูดีกว่า แต่เราจะส่งผ่านพารามิเตอร์ได้อย่างไร
msanjay

3
@msanjay คุณสามารถส่งผ่านเป็นพารามิเตอร์อื่น ๆ ไปยัง url_for ยกตัวอย่างเช่นจะส่งผลให้redirect_to url_for(:controller => :controller_name, :action => :action_name, :param1 => :val1, :param2 => :val2) /contorller_name/action_name?param1=val1&param2=val2ดูเอกสาร
Ariel Allon

ถ้าฉันพยายาม redirect_ ไปยัง root controller เช่น "MyOtherController" จากคอนโทรลเลอร์เช่น "Module :: MyController" .. มันจะเปลี่ยนเป็นการเรียก "module / MyOtherController" .. มีความคิดอย่างไรที่จะเรียก root ได้?
ggez44

12

นี่เป็นแนวทางปฏิบัติที่ไม่ดีในการเรียกการกระทำของคอนโทรลเลอร์อื่น

คุณควร

  1. ทำซ้ำการกระทำนี้ในคอนโทรลเลอร์ B ของคุณหรือ
  2. ห่อเป็นวิธีการแบบจำลองที่จะแชร์กับตัวควบคุมทั้งหมดหรือ
  3. คุณสามารถขยายการกระทำนี้ได้ในตัวควบคุม A

ความคิดเห็นของฉัน:

  1. แนวทางแรกไม่แห้ง แต่ก็ยังดีกว่าเรียกร้องให้ดำเนินการอื่น
  2. แนวทางที่สองดีและยืดหยุ่น
  3. แนวทางที่สามคือสิ่งที่ฉันเคยทำบ่อยๆ ผมจะแสดงตัวอย่างเล็ก ๆ น้อย ๆ

    def create
      @my_obj = MyModel.new(params[:my_model])
      if @my_obj.save
        redirect_to params[:redirect_to] || some_default_path
       end
    end

ดังนั้นคุณสามารถส่งไปยังredirect_toพารามิเตอร์การดำเนินการนี้ซึ่งอาจเป็นเส้นทางใดก็ได้ที่คุณต้องการ


สวัสดีครับสำหรับวิธีแก้ B wrap เป็น model method จะสรุปยังไงถ้าไม่มี model เลย? เรากำลังทำงานกับเครื่องมือค้นหาและต้องการเรียกการดูการค้นหาในเครื่องมือค้นหาจากเครื่องมืออื่น ๆ ไม่มีโมเดลข้อมูลสำหรับการดำเนินการค้นหาเลย
user938363

@ user938363 - อาจมีทั้งสองการกระทำทั้งสองอย่างแสดงมุมมองเดียวกัน (แม้ว่าการกระทำเหล่านั้นจะอยู่ในตัวควบคุมที่ต่างกันก็ตาม) การเรียก "เรนเดอร์" จะซ้ำกัน แต่ในตัวมันเองเป็นเพียงบรรทัดเดียวของการทำซ้ำ - ไม่เลวร้ายนัก หากคุณมีตรรกะจำนวนมากที่เตรียมแฮชของพารามิเตอร์เพื่อส่งผ่านไปยังการเรียกใช้การเรนเดอร์คุณสามารถหลีกเลี่ยงการทำซ้ำได้โดยย้ายไปไว้ในไฟล์ของตัวเอง (อาจจะเป็นโมเดลใน/modelsหรือคลาสธรรมดาหรือโมดูลใน/lib) ปัญหาเดียวคือถ้าคอนโทรลเลอร์ของคุณสื่อสารกับมุมมองผ่านตัวแปรอินสแตนซ์คุณต้องแก้ไขการทำซ้ำด้วยวิธีอื่น
antinome

จะเกิดอะไรขึ้นถ้าคุณมี UserController ที่สร้างผู้ใช้ใหม่ (การลงทะเบียน) และเมื่อสำเร็จคุณต้องการเรียกใช้ SessionsController และรับรองความถูกต้องของผู้ใช้? ในกรณีนี้คุณไม่ทางใดก็ทางหนึ่งเรียกใช้ SessionsController มีความคิดเห็นเกี่ยวกับเรื่องนี้ไหม
dipole_moment

ทำไมถึงปฏิบัติไม่ดี Sammy Lambi มีปัญหาอะไรกับคำตอบ?
vasilakisfil

7

บางทีตรรกะอาจถูกดึงออกมาเป็นตัวช่วย? ผู้ช่วยเหลือสามารถใช้ได้กับทุกชั้นเรียนและไม่ต้องโอนการควบคุม คุณสามารถตรวจสอบภายในบางทีอาจเป็นชื่อคอนโทรลเลอร์เพื่อดูว่ามันถูกเรียกอย่างไร


6

องค์ประกอบเพื่อการช่วยเหลือ!

ด้วยเหตุผลแทนที่จะเรียกใช้การดำเนินการกับตัวควบคุมเราควรออกแบบตัวควบคุมเพื่อแยกส่วนที่ใช้ร่วมกันและส่วนที่กำหนดเองของโค้ด สิ่งนี้จะช่วยหลีกเลี่ยงทั้งการทำซ้ำรหัสและการทำลายรูปแบบ MVC

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

# controllers/a_controller.rb
class AController < ApplicationController
  include Createable

  private def redirect_url
    'one/url'
  end
end

# controllers/b_controller.rb
class BController < ApplicationController
  include Createable

  private def redirect_url
    'another/url'
  end
end

# controllers/concerns/createable.rb
module Createable
  def create
    do_usefull_things
    redirect_to redirect_url
  end
end

หวังว่าจะช่วยได้


2

คุณสามารถเรียกการดำเนินการอื่นภายในการดำเนินการดังต่อไปนี้:

redirect_to action: 'action_name'

class MyController < ApplicationController
  def action1
   redirect_to action: 'action2'
  end

  def action2
  end
end

-6

แยกฟังก์ชันเหล่านี้ออกจากคอนโทรลเลอร์และใส่ไว้ในไฟล์โมเดล จากนั้นรวมไฟล์โมเดลในคอนโทรลเลอร์ของคุณ


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