Рейки: викликайте іншу дію контролера від контролера


118

Мені потрібно викликати дію створення в контролері A, від контролера B.

Причина в тому, що мені потрібно переадресовувати інакше, коли я дзвоню з контролера B.

Чи можна це зробити в Rails?



Ви говорите про POST або GET дії? Якщо GET, ви можете просто переспрямувати на цю дію. Але причина цього не є зрозумілою, оскільки ви можете перенаправлятись з контролера A на будь-який URL-адресу, який ви хочете.
Волді

Відповіді:


64

Ви можете використовувати переспрямування до цієї дії:

redirect_to your_controller_action_url

Детальніше про: Посібник по рейках

Щоб просто виконати нову дію:

redirect_to your_controller_action_url and return

5
Вибачте, але чи можете ви сказати, яка різниця між першим і другим рядком? Думаю, спочатку виконати решта рядків коду, а потім перенаправити. Це правильно?
акс

Я думаю, що, можливо, останній приклад був помилковим, а renderзамість цього повинен бути redirect_to. Що ти скажеш, @Spyros?
Магне

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 - му рядку. Це ти просиш?
Семмі Ларбі

1
пробували в рейках 5, для надання його повинно бутиrender html: controller_you_want.process(:action_you_want)
nazar kuliyev

41

Логіка, яку ви представляєте, не MVC, то не Rails, сумісна.

  • Контролер надає перегляд або переадресацію

  • Метод виконує код

З цих міркувань раджу створити методи у своєму контролері та викликати їх у своїй дії.

Приклад:

 def index
   get_variable
 end

 private

 def get_variable
   @var = Var.all
 end

Це означає, що ви можете зробити точно так само через різні контролери та викликати метод з контролера A, поки ви перебуваєте в контролері B.

Лексика надзвичайно важлива, тому я дуже наполягаю.


Я знаю, що не повинен цього робити, але це не частина моєї заявки, а лише для тестування та оцінки моєї програми.
день

9
Любіть .. відокремте метод від візуалізації, а потім зателефонуйте окремому методу, де потрібно. Лише одне питання .. як get_variableтепер можна телефонувати з іншого контролера?
FloatingRock

1
@FloatingRock щойно помітив ваше запитання / коментар: у вас є кілька варіантів: можна визначити спільного предка або ви можете включити звичайний міксин
apneadiving

люблю відповідь, не впевнений у фрагменті засудженого речення
Джерард Сімпсон,

30

Ви можете використовувати url_forURL-адресу для контролера та дії, а потім 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. Дивіться документи
Аріель Аллон

якщо я спробую перенаправити_до кореневого контролера типу "MyOtherController", з контролера типу "Модуль :: MyController" .. це вирішить викликати "модуль / MyOtherController" .. будь-яка ідея, як я можу викликати корінь?
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 як модельного методу, як завершити, якщо моделі взагалі немає? Ми працюємо над пошуковою системою і хотіли б зателефонувати в пошуковій системі з інших пошукових систем. Модель даних для пошукової дії взагалі не існує.
user938363

@ user938363 - Можливо, обидві дії надають однаковий вигляд (навіть якщо ці дії є в різних контролерах). Сам виклик "візуалізації" буде дублюватися, але сам по собі це лише одна лінія дублювання - не так вже й погано. Якщо у вас є багато логіки, яка готує хеш параметрів для передачі виклику візуалізації, ви можете уникнути дублювання цього, перемістивши його у свій власний файл (можливо, модель у /modelsабо звичайний клас чи модуль в /lib). Єдина проблема - якщо ваш контролер спілкується з представленням через змінні екземпляра - вам доведеться виправити це дублювання іншим способом.
antinome

Що робити, якщо у вас є UserController, який створює нового Користувача (реєстрацію), і після успіху ви хочете викликати SessionsController і автентифікувати користувача? У цьому випадку ви так чи інакше викликаєте SessionsController. Будь-які думки з цього приводу?
dipole_moment

Чому це погана практика? у чому проблема з відповіддю Семмі Ламбі?
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

Ви можете викликати іншу дію всередині дії таким чином:

перенаправлення_до дії: 'ім'я дії'

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

  def action2
  end
end

-6

Відокремте ці функції від контролерів і помістіть їх у файл моделі. Потім додайте файл моделі у свій контролер.


Погана пропозиція. Позбудуться обов'язків, вкажіть на MVC. Проблеми з дзвінками з сеансу / cookie в моделі тощо
Ain Tohvri
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.