在模型中访问Rails的flash[:notice]

15

我正在尝试在模型观察器中将消息分配给flash[:notice]。

这个问题已经被问过了:Ruby on Rails:观察器和flash[:notice]消息?

但是,当我尝试在我的模型中访问它时,我会得到以下错误信息:

undefined local variable or method `flash' for #<ModelObserver:0x2c1742c>

这是我的代码:

class ModelObserver < ActiveRecord::Observer
  observe A, B, C

  def after_save(model)
    puts "Model saved"
    flash[:notice] = "Model saved"
  end
end

我知道方法已被调用,因为“Model saved”被打印到终端。

在观察者中是否可以访问闪存,如果可以,如何访问?


2
在技术上有效的解决方案中,破坏了MVC:https://dev59.com/questions/u3RC5IYBdhLWcg3wKtr2#608700 - titaniumdecoy
2个回答

19

不,你需要在执行保存操作的控制器中设置。 flash 是在 ActionController::Base 上定义的方法。


7
虽然Ryan说的没错,但你应该在控制器中设置闪存...它是视图呈现层的功能。上面的“答案”需要进行很多危险而繁重的工作才能使其正常工作。 - Toby Hede
1
正如我在帖子中所说,对于我的应用程序来说,在控制器中设置闪存是不切实际的(如果可能的话)。每次更新模型时,我需要向闪存添加一条消息;我不知道还有其他方法可以这样做--至少不会让代码变得混乱。 - titaniumdecoy
我今天也稍微与这个问题搏斗了一下,但是在解决了我的困境之后,我看到你在我的评论正上方回答了你的问题。“每次更新模型时,我需要向Flash添加一条消息。” 我知道你说它不切实际,但我把我的Flash放在控制器的update方法中。(捕获异常,然后闪烁错误。) - Tass
6
有时候世界并不像你希望的那样简单。我需要将来自一个monkey patched扩展的闪存设置为Sunspot/RSolr,该扩展在请求周期内由模型回调触发,并在不同线程中执行。请不要给出显而易见的答案。你可以提到通常的做法,但除非它直接回答问题,否则它并没有任何帮助。 - Chloe
$0.02 -> 当你认为你“必须”以一种“肮脏的”(或不可扩展的、有风险的或过于复杂的)方式做某事时,很可能是因为你在某个地方“抽象化错误”。包含此场景的架构需要重构。选择违反惯例,因为你觉得你“必须”这样做,可能会导致几个月或几年后陷入困境(我也不主张将尾部风险推给未来的开发人员)。简而言之,就像Ryan Bigg所说的那样。 - Todd
2
我认为定义一个模型的attr_accessor,例如validation_messages,然后在控制器的after_action回调中检查它,根据validation_messages的值设置flash(在控制器内部)是没有问题的。 - Darme

14

我需要在模型中设置flash[:notice]来覆盖通用的" @model成功更新"。

我做了以下几步:

  1. 在相应的模型中创建了一个虚拟属性,名为validation_message
  2. 当需要时,在相应的模型中设置虚拟属性
  3. 使用after_action,在此虚拟属性不为空时覆盖默认的闪现提示

您可以看到下面是我的控制器和模型,以了解我完成这个过程的具体实现:

class Reservation < ActiveRecord::Base

  belongs_to :retailer
  belongs_to :sharedorder
  accepts_nested_attributes_for :sharedorder
  accepts_nested_attributes_for :retailer

  attr_accessor :validation_code, :validation_messages

  validate :first_reservation, :if => :new_record_and_unvalidated

  def new_record_and_unvalidated
    if !self.new_record? && !self.retailer.validated?
      true
    else
      false
    end
  end

  def first_reservation
    if self.validation_code != "test" || self.validation_code.blank?
      errors.add_to_base("Validation code was incorrect") 
    else
      self.retailer.update_attribute(:validated, true)
      self.validation_message = "Your validation is successful and you will not need to do that again"
    end
  end
end

class ReservationsController < ApplicationController

  before_filter :authenticate_retailer!
  after_filter :validation_messages, :except => :index

  def validation_messages
    return unless @reservation.validation_message.present?

    flash[:notice] = @reservation.validation_message
  end
end

一种可能的重构方法是将实际消息移至适当的文件(例如本地化文件),并仅传递正确的键给validation_message

如果需要多个通知,则可以将validation_message轻松转换为数组或哈希,并改称validation_messages


1
你可以将if条件简化为@reservation.flash_notice.present?而不是使用“not blank?”。 - Besi

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接