В вашем 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% свободными от логики.