【问题标题】:How to call ActionMailer method in aasm callback?如何在 aasm 回调中调用 ActionMailer 方法?
【发布时间】:2023-03-27 17:49:01
【问题描述】:

我正在学习 ruby​​ on rails,但在使用 aasm 回调和 actionmailer 时遇到了问题。 我有一个酒店模型。这是一个代码:

class Hotel < ActiveRecord::Base
  include AASM

  scope :approved_hotels, -> { where(aasm_state: "approved") }

  has_many :comments
    belongs_to :user, :counter_cache => true
    has_many :ratings
  belongs_to :address

  aasm do
    state :pending, initial: true
    state :approved
    state :rejected

    event :approve, :after => :send_email do
      transitions from: :pending, to: :approved 
    end
    event :reject, :after => :send_email do
      transitions from: :pending, to: :rejected
    end
  end

  def send_email

  end
end

如您所见,当他添加的酒店状态发生更改时,用户必须收到电子邮件。这是我写的,但它不是解决方案,因为每次管理员以“待定”状态更新酒店时,用户都会收到电子邮件。

class HotelsController < ApplicationController
  before_filter :authenticate_user!, except: [:index, :show, :top5hotels]

  def update
    @hotel = Hotel.find(params[:id])

    if @hotel.aasm_state == "pending"
      @hotel.aasm_state = params[:state]
      UserMailer.changed_state_email(current_user, @hotel.name, 
      @hotel.aasm_state).deliver
    end

    if @hotel.update_attributes!(params[:hotel])
      redirect_to admin_hotel_path(@hotel), notice: "Hotel was successfully updated."
    else
      render "edit"
    end
  end
end

所以我想我需要使用回调,但我不知道如何调用

UserMailer.changed_state_email(current_user, @hotel.name, 
        @hotel.aasm_state).deliver

来自模型。 我试过了

UserMailer.changed_state_email(User.find(:id), Hotel.find(:name), 
        Hotel.find(aasm_state)).deliver

但这不起作用。 我真的没有选择并寻求任何帮助。 谢谢!

【问题讨论】:

    标签: ruby-on-rails callback actionmailer aasm


    【解决方案1】:

    您不能使用回调,因为您有 current_user 这是控制器上下文的一部分,并且您无法访问模型上下文中的请求信息。

    无论如何,即使您可以使用回调,在这种情况下,我强烈建议您采用不同的方式。应该很少使用 ActiveRecord 回调,特别是对于涉及与其他对象或资源(例如邮件程序或级联更新)交互的任何代码,您应该避免使用它们。风险在于,即使您不需要它(例如测试)也会触发回调,从而增加开销,或者当项目的复杂性增加时它会与其他回调发生冲突。

    在这种情况下,解决方案非常简单。在模型中定义一个新方法(我暂时不向您介绍服务对象......),您可以使用它来更改状态和发送电子邮件。

    class Hotel
      def user_state_change(user, new_state)
        return unless pending? && new_state.present?
    
        if update_attribute(:aasm_state, new_state)
          UserMailer.changed_state_email(user, name, aasm_state).deliver
        end
      end
    end
    

    你的控制器会变成

    class HotelsController < ApplicationController
      before_filter :authenticate_user!, except: [:index, :show, :top5hotels]
    
      def update
        @hotel = Hotel.find(params[:id])
        @hotel.user_state_change(current_user, params[:state])
    
        if @hotel.update_attributes!(params[:hotel])
          redirect_to admin_hotel_path(@hotel), notice: "Hotel was successfully updated."
        else
          render "edit"
        end
      end
    end
    

    附带说明,您可能希望使用状态机转换方法,而不是更改状态属性。事实上,使用状态机转换将确保触发转换验证。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2012-04-10
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2022-07-15
      • 1970-01-01
      相关资源
      最近更新 更多