rails 4 выводит контроллер из строя из-за одиночной ошибки рендеринга

#ruby-on-rails #ruby #ruby-on-rails-4 #dry

#ruby-on-rails #ruby #ruby-on-rails-4 #сухой

Вопрос:

Может быть, это излишество, я но я пытаюсь использовать after_filter для вывода этого контроллера из строя. К моему ужасу, он взрывается, и я не могу понять, почему. Чтобы заставить его работать, мне пришлось добавить рендеринг в каждый метод.

Мысли?

Сообщение об ошибке

Рендеринг и / или перенаправление вызывались несколько раз в этом действии. Пожалуйста, обратите внимание, что вы можете вызывать render ИЛИ redirect только не чаще одного раза за действие. Также обратите внимание, что ни перенаправление, ни рендеринг не завершают выполнение действия, поэтому, если вы хотите завершить действие после перенаправления, вам нужно сделать что-то вроде «redirect_to(…) и return».

Контроллер

 class ErrorController < ApplicationController
  after_filter :render_me

  def javascript_disabled
    @title = 'Error! Javascript Disabled'
  end

  def system_requirements
    @title = 'Error! System Requirements'
  end

  def browser_upgrade_required
    @title = 'Error! Browser Upgrade Required'
  end

  private

  def render_me
    render 'error/system_requirements', layout: 'error'
  end

end
  

Маршрут

   scope 'error' do
    get '/javascript-disabled', to: 'error#javascript_disabled'
    get '/software-requirements', to: 'error#system_requirements'
    get '/browser-upgrade-required', to: 'error#browser_upgrade_required'
  end
  

Ответ №1:

Проблема в том, что рендеринг не останавливает выполнение в вашем методе. В вашем render_me методе вы вызываете render, а затем выполнение продолжается в вызываемом методе action … в конце которого есть встроенный рендеринг.

Вы можете исправить это, самостоятельно вызывая свой метод after_filter в каждом действии и добавляя явный возврат для остановки выполнения, например:

 class ErrorController < ApplicationController
  def javascript_disabled
    @title = 'Error! Javascript Disabled'
    render_me
  end

  def system_requirements
    @title = 'Error! System Requirements'
    render_me
  end

  def browser_upgrade_required
    @title = 'Error! Browser Upgrade Required'
    render_me
  end

  private

  def render_me
    render 'error/system_requirements', layout: 'error'
  end
end
  

Конечно, вы могли бы немного это исправить:

 class ErrorController < ApplicationController
  def javascript_disabled
    render_with_error 'Error! Javascript Disabled'
  end

  def system_requirements
    render_with_error 'Error! System Requirements'
  end

  def browser_upgrade_required
    render_with_error 'Error! Browser Upgrade Required'
  end

  private

  def render_with_error(msg)
    @title = msg
    render 'error/system_requirements', layout: 'error'
  end
end
  

Я склонен считать, что если вам нужно повторно исправить кодовую базу rails, вы, вероятно, делаете что-то неправильно.

Комментарии:

1. Я только что попробовал это, и я все еще получаю ошибку: «Рендеринг и / или перенаправление были вызваны несколько раз в этом действии. Пожалуйста, обратите внимание, что вы можете вызывать render ИЛИ redirect только не чаще одного раза за действие. Также обратите внимание, что ни перенаправление, ни рендеринг не завершают выполнение действия, поэтому, если вы хотите завершить действие после перенаправления, вам нужно сделать что-то вроде «redirect_to(…) и return».

2. Моя ошибка — по какой-то причине у меня была полная заморозка мозга, и я ответил на это так, как если бы это было before_filter . Я обновил свой ответ для вас. Я думаю, что это лучше, чем обезьянье исправление render метода TBH.

3. о, мне это очень нравится. Спасибо:)

4. Кстати, and return в конце метода бессмысленно.

5. Да, верно — похмелье от моего первоначального плохо написанного ответа.

Ответ №2:

На случай, если другие найдут этот пост, вот другой подход, который вы можете предпринять, чтобы его исправить:

 class ErrorController < ApplicationController

  def javascript_disabled
    @title = 'Error! Javascript Disabled'
    render_it
  end

  def system_requirements
    @title = 'Error! System Requirements'
    render_it
  end

  def browser_upgrade_required
    @title = 'Error! Browser Upgrade Required'
    render_it
  end

  private

  def render_it
    render 'error/system_requirements', layout: 'error'
  end

end
  

Ответ №3:

У вас уже есть неявный #render вызов в действиях контроллера. Итак, после того, как filter вызывает #render еще раз явно, и вы получаете DoubleRenderError.

Вы можете переопределить #render подобный метод

 def render(*args)
  if args.blank? amp;amp; !block_given?
    # default template
    super('error/system_requirements', layout: 'error')
  else
    super
  end
end
  

Я думаю, что это лучше, чем использовать обратные вызовы, иначе называемые фильтрами.

Комментарии:

1. это довольно сумасшедший подход. Интересно, будут ли другие разработчики злоупотреблять этим, но мне нравится это решение. хммм…

2. Как я уже сказал в своем ответе, если вы исправляете кодовую базу rails, я думаю, вы, вероятно, делаете что-то неправильно.

3. Это не патч для обезьяны. Это Ruby. Это наследование. Rails не предоставляет вам возможности установить вид по умолчанию для контроллера, но Ruby это делает.

4. @FlashGordon Rails does not provide you ability to set default view for controller это неправильно. AbstractController#append_view_path

5. @Зелёный Ok. Не могли бы вы опубликовать суть с примером?