Rails: panggil tindakan pengontrol lain dari pengontrol

118

Saya perlu memanggil tindakan buat di pengontrol A, dari pengontrol B.

Alasannya adalah saya perlu mengalihkan secara berbeda ketika saya menelepon dari pengontrol B.

Bisakah itu dilakukan di Rails?

ddayan
sumber
Apakah Anda berbicara tentang tindakan POST atau GET? Jika GET Anda dapat langsung mengarahkan ke tindakan itu. Tetapi alasan untuk itu tidak cukup jelas karena Anda dapat mengalihkan dari pengontrol A ke url apa pun yang Anda inginkan.
Voldy
kemungkinan duplikat Memanggil pengontrol dari yang lain
Ciro Santilli 郝海东 冠状 病 六四 事件 法轮功

Jawaban:

64

Anda dapat menggunakan pengalihan ke tindakan itu:

redirect_to your_controller_action_url

Lebih lanjut tentang: Panduan Rel

Untuk hanya membuat tindakan baru:

redirect_to your_controller_action_url and return
Spyros
sumber
5
Maaf, tapi bisakah Anda membedakan baris pertama dan baris kedua? Saya pikir pertama-tama akan mengeksekusi baris kode yang tersisa dan kemudian mengarahkan ulang. Apakah itu benar?
aks
Saya berpikir mungkin contoh terakhir adalah salah ketik dan seharusnya menjadi rendergantinya redirect_to. Apa yang Anda katakan, @Spyros?
Magne
1
Hai @spyros, redirect_totidak mengizinkan untuk menggunakan post: :methoddan ini dapat berguna terutama untuk mengarahkan ke tindakan yang sudah ada createdari pengontrol lain seperti yang diminta @ddayan pada saat pertama. Saya memiliki situasi serupa di mana dalam beberapa situasi saya harus membuat objek lain. Memanggil createtindakan lain bisa jadi LEBIH KERING ..
SanjiBukai
53

Untuk menggunakan satu pengontrol dari yang lain, lakukan ini:

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
Sammy Larbi
sumber
18
Jika Anda ingin callback tetap dijalankan, controller_you_wantAnda akan melakukannyacontroller_you_want.process(:action_you_want)
Constantijn Schepens
3
Terima kasih! Ini sangat membantu untuk situasi di mana Anda tidak ingin mengalihkan, Anda hanya memerlukan solusi cepat untuk mengadopsi tindakan dari satu pengontrol ke lainnya. Mengarahkan benar-benar sesuatu yang berbeda. Juga: render status: :ok, json: JSON.parse(controller.render(:action_you_want).first)tampaknya berfungsi untuk mengembalikan JSON dari pengontrol lain
Yourpalal
1
Jawaban yang bagus, apa yang saya cari. Satu pertanyaan - format apa yang dibutuhkan parameter permintaan di sini? Saya berasumsi mereka tinggal di bawah controller_you_want.requesttetapi tidak bisa mendapatkan penembakan ini melalui hash atau parameter contoh.
SRack
Saya tidak yakin apa yang Anda tanyakan @SRack. The paramsmenjadi tersedia untuk controller_you_wantdengan menetapkan requestdi garis-3. Itukah yang kamu tanyakan?
Sammy Larbi
1
mencoba di rel 5, untuk rendering itu harusrender html: controller_you_want.process(:action_you_want)
nazar kuliyev
41

Logika yang Anda sajikan bukanlah MVC, bukan Rails, yang kompatibel.

  • Sebuah pengontrol membuat tampilan atau pengalihan

  • Sebuah metode menjalankan kode

Dari pertimbangan ini, saya menyarankan Anda untuk membuat metode di pengontrol Anda dan memanggilnya dari tindakan Anda.

Contoh:

 def index
   get_variable
 end

 private

 def get_variable
   @var = Var.all
 end

Yang mengatakan Anda dapat melakukan hal yang persis sama melalui pengontrol yang berbeda dan memanggil metode dari pengontrol A saat Anda berada di pengontrol B.

Kosakata sangat penting, itulah mengapa saya bersikeras.

apneadiving
sumber
Saya tahu saya seharusnya tidak melakukan itu, tetapi ini bukan bagian dari aplikasi saya, ini hanya untuk menguji dan mengevaluasi aplikasi saya.
ddayan
9
Suka .. pisahkan metode dari render, lalu panggil metode individual jika diperlukan. Hanya satu pertanyaan .. bagaimana get_variablesekarang bisa dipanggil dari pengontrol lain?
FloatingRock
1
@FloatingRock baru saja memperhatikan pertanyaan / komentar Anda: Anda memiliki beberapa opsi: dapat didefinisikan dalam leluhur yang sama atau Anda dapat menyertakan campuran umum
apneadiving
suka jawabannya, tidak yakin tentang fragmen kalimat yang membuntut
Gerard Simpson
30

Anda dapat menggunakan url_foruntuk mendapatkan URL untuk pengontrol dan tindakan dan kemudian menggunakan redirect_tountuk pergi ke URL itu.

redirect_to url_for(:controller => :controller_name, :action => :action_name)
austin
sumber
1
yang lain sepertinya tidak berhasil untuk saya, ini terlihat lebih baik, tetapi bagaimana kita melewatkan parameter?
msanjay
3
@ msanjay Anda dapat meneruskannya sebagai parameter lain ke url_for. Misalnya redirect_to url_for(:controller => :controller_name, :action => :action_name, :param1 => :val1, :param2 => :val2)akan menghasilkan /contorller_name/action_name?param1=val1&param2=val2. Lihat dokumen
Ariel Allon
jika saya mencoba untuk mengarahkan_ke pengontrol root seperti "MyOtherController", dari pengontrol seperti "Module :: MyController" .. itu akan memutuskan untuk memanggil "modul / MyOtherController" .. ada ide bagaimana saya dapat memanggil root?
ggez44
12

Ini adalah praktik yang buruk untuk memanggil tindakan pengontrol lainnya.

Kamu harus

  1. duplikat tindakan ini di pengontrol B Anda, atau
  2. membungkusnya sebagai metode model, yang akan dibagikan ke semua pengontrol, atau
  3. Anda dapat memperluas tindakan ini di pengontrol A.

Pendapat saya:

  1. Pendekatan pertama tidak KERING tetapi masih lebih baik daripada meminta tindakan lain.
  2. Pendekatan kedua baik dan fleksibel.
  3. Pendekatan ketiga adalah apa yang sering saya lakukan. Jadi saya akan menunjukkan sedikit contoh.

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

Jadi, Anda dapat mengirim ke redirect_toparameter tindakan ini , yang dapat berupa jalur mana pun yang Anda inginkan.

fl00r
sumber
Hai, untuk solusi B bungkus sebagai metode model, bagaimana cara membungkus jika tidak ada model sama sekali? Kami sedang mengerjakan mesin pencari dan ingin memanggil tampilan pencarian di mesin pencari dari mesin lain. Tidak ada model data sama sekali untuk tindakan pencarian.
user938363
@ user938363 - Mungkin memiliki dua tindakan yang membuat tampilan yang sama (meskipun tindakan tersebut berada dalam pengontrol yang berbeda). Panggilan "render" itu sendiri akan diduplikasi tetapi itu sendiri hanya satu baris duplikasi - tidak terlalu buruk. Jika Anda memiliki banyak logika yang menyiapkan hash parameter untuk diteruskan ke panggilan render, Anda dapat menghindari duplikatnya dengan memindahkannya ke file sendiri (mungkin model di /modelsatau kelas biasa atau modul di /lib). Satu-satunya masalah adalah jika pengontrol Anda berkomunikasi dengan view melalui variabel instan - Anda harus memperbaiki duplikasi itu dengan cara lain.
antinome
Bagaimana jika Anda memiliki UserController yang membuat Pengguna baru (registrasi) dan setelah berhasil Anda ingin memanggil SessionsController dan mengautentikasi pengguna? Dalam hal ini, Anda dengan satu atau lain cara menjalankan SessionsController. Ada pemikiran tentang ini?
dipole_moment
Mengapa ini praktik yang buruk? apa masalahnya dengan jawaban Sammy Lambi?
vasilakisfil
7

Mungkin logika bisa diekstraksi menjadi penolong? pembantu tersedia untuk semua kelas dan tidak mentransfer kontrol. Anda dapat memeriksa di dalamnya, mungkin untuk nama pengontrol, untuk melihat bagaimana itu dipanggil.

Michael Durrant
sumber
6

Komposisi untuk menyelamatkan!

Mengingat alasannya, daripada meminta tindakan di seluruh pengontrol, seseorang harus merancang pengontrol untuk memisahkan bagian kode yang dibagikan dan kustom. Ini akan membantu menghindari keduanya - duplikasi kode dan pemutusan pola MVC.

Meskipun itu bisa dilakukan dengan berbagai cara, menggunakan perhatian ( komposisi ) adalah praktik yang baik.

# 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

Semoga membantu.

Oleg Afanasyev
sumber
2

Anda dapat memanggil tindakan lain di dalam tindakan sebagai berikut:

redirect_to action: 'action_name'

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

  def action2
  end
end
CodecPM
sumber
-6

Pisahkan fungsi-fungsi ini dari pengontrol dan masukkan ke dalam file model. Kemudian sertakan file model di pengontrol Anda.

Michale.Gaocl
sumber
Saran yang buruk. Akan mengacaukan tanggung jawab, maksudnya memiliki MVC. Masalah dengan sesi / panggilan cookie dalam model dll.
Ain Tohvri