Вызов данных из частичного в контроллере без запуска нескольких рендеров / перенаправлений - PullRequest
1 голос
/ 19 сентября 2019

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

Так выглядит метод create в контроллере, который вызывает другую функцию.

def create
  @finding = @findings.new(finding_params)
  respond_to do |format|
    if @finding.save
      if @project_notifications.where(category: "XXXXXXX").any?
        notify_users(1)
      end
      flash[:notice] = 'Finding was successfully created.'
    else
      helpers.show_errors_for(@finding)
    end
    format.html { redirect_back fallback_location: root_path }
    format.js { head :no_head }
  end
end

Функция notify_users выглядит следующим образом:

def notify_users(notification_type)
  if notification_type == 1
    html_body = render(partial: 'findings/added_finding')
    subject = "XXXXXXX."

    @project_notifications.each do |notification|
      NotificationWorker.perform_async(html_body, notification.user, subject)
    end
  end
end

Проблема в том, что я отключаю несколько ошибок рендеринга / перенаправления.Есть ли способ извлечь данные из частичного без повторного вызова render?

Ответы [ 2 ]

2 голосов
/ 20 сентября 2019

Я почти уверен, что вы можете использовать render_to_string для этого варианта использования:

def notify_users(notification_type)
  if notification_type == 1
    html_body = render_to_string(partial: 'findings/added_finding', layout: false)
    subject = "XXXXXXX."

    @project_notifications.each do |notification|
      NotificationWorker.perform_async(html_body, notification.user, subject)
    end
  end
end

Таким образом, вы получите строковое представление вашего HTML для использования в другом месте.Дайте мне знать, как вы справляетесь с этим - мне интересно знать, подходит ли это вашему варианту использования.И любые вопросы, огонь уйти :) 1007 *

2 голосов
/ 19 сентября 2019

В вашем notify_users методе (не в функции) вы вызываете render здесь:

html_body = render(partial: 'findings/added_finding')

А в вашем create методе вы вызываете redirect здесь:

format.html { redirect_back fallback_location: root_path }

Таким образом, казалось бы, что выражение:

Render и / или redirect были вызваны несколько раз в этом действии.

... верно.

Полагаю, вы могли бы переместить notify_user на NotifyUserService и выполнить там рендеринг.Когда я оказываю услуги, у меня нет проблемы Render and/or redirect were call multiple times.

Итак, вы можете сделать что-то вроде:

#app/services/notify_user_service.rb
class NotifyUserService

  include ActsAsRendering

  class << self 

    def call(args={})
      new(args).call
    end

  end

  def initialize(args)
    args.each do |k,v|
      class_eval do 
        attr_accessor k
      end
      send("#{k}=",v)
    end
  end

  def call 
    case notification_type
    when :some_notification_type
      html_body = render_partial('findings/added_finding')
      subject = "XXXXXXX."

      project_notifications.each do |notification|
        NotificationWorker.perform_async(html_body, notification.user, subject)
      end          
    end
  end

  def some_information
    case notification_type
      when :some_notification_type
        'some notification information'
      else
        'default notification information'
      end
  end

end

Затем, в вашем контроллере,

def create
  @finding = @findings.new(finding_params)
  respond_to do |format|
    if @finding.save
      if @project_notifications.where(category: "XXXXXXX").any?
        NotifyUserService.call(
          notification_type: :some_notification_type, 
          project_notifications: @project_notifications
        )
      end
      flash[:notice] = 'Finding was successfully created.'
    else
      helpers.show_errors_for(@finding)
    end
    format.html { redirect_back fallback_location: root_path }
    format.js { head :no_head }
  end
end

Это, естественно, предполагает, что NotifyUserService знает, как render.Я забыл, в каком состоянии находится рендеринг в любом месте мира Rails 5/6.Но, чтобы сообщить своим службам, как render, у меня есть модуль, который называется что-то вроде ActsAsRendering:

#app/acts_as/acts_as_rendering.rb
#------------------------------------------------------------------------------------------------
# Use like: 
#   include ActsAsRendering
#------------------------------------------------------------------------------------------------
module ActsAsRendering

  module ClassMethods

  end

  module InstanceMethods

  private

    def action_view
      @action_view ||= new_action_view 
    end

    def new_action_view
      av = ActionView::Base.new
      av.view_paths = ActionController::Base.view_paths
      av.class_eval do
        include Rails.application.routes.url_helpers
        include ApplicationHelper
      end
      av
    end

    def method_missing(meth, *params, &block)
      if action_view.respond_to?(meth)
        action_view.send(meth, *params, &block)
      else
        super
      end
    end

    def render_partial(file_name)
      file_name = file_name.to_s
      render(partial: file_name, locals: {presenter: self})
    end

  end

  def self.included(receiver)
    receiver.extend   ClassMethods
    receiver.include  InstanceMethods
  end
end

Вы заметите, что я создал render_partial метод и использую его вместо render.Метод render_partial принимает экземпляр NotifyUserService в качестве локального.Таким образом, на мой взгляд, я могу делать такие вещи, как:

#app/views/findings/added_finding.html.haml
- @presenter = local_assigns[:presenter] if local_assigns[:presenter]

#some-document-id
  .some-presenter-information
    @presenter.some_information

И теперь в представлении будет отображаться «некоторая информация об уведомлении» в html.Таким образом, я могу вставить all логика просмотра обратно в докладчик, и мои представления станут на 100% свободными от логики.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...