Rails: 一次添加多个 flash[:notice] 的简便方法

51

我认为每次执行flash[:notice]="Message"都会将其添加到数组中,然后在视图中显示,但是下面的代码只保留了最后一个flash:

flash[:notice] = "Message 1"
flash[:notice] = "Message 2"

现在我意识到这只是一个带有键的简单哈希(我想 :)),但除了以下方法之外,是否有更好的方法来进行多个闪存:

flash[:notice] = "Message 1<br />"
flash[:notice] << "Message 2"

2
小心Cookie溢出。 - Ziggy
@Ziggy 是的!谢谢你。我上周遇到了这个问题,所以你的时机很好。最终我改为使用 ActiveRecord 会话存储来处理更大的会话数据,参考:http://guides.rubyonrails.org/security.html#session-storage - Joshua Pinter
10个回答

64

我通常会将这样的方法添加到我的ApplicationHelper中:

def flash_message(type, text)
    flash[type] ||= []
    flash[type] << text
end

并且

def render_flash
  rendered = []
  flash.each do |type, messages|
    messages.each do |m|
      rendered << render(:partial => 'partials/flash', :locals => {:type => type, :message => m}) unless m.blank?
    end
  end
  rendered.join('<br/>')
end

然后使用它们非常容易:

您可以编写类似于以下内容的代码:

flash_message :notice, 'text1'
flash_message :notice, 'text2'
flash_message :error, 'text3'

在你的控制器中实现。

只需在你的布局中添加这一行:

<%= render_flash %>

1
谢谢Victor,这是一个更全面的答案。我想一个人可以使它尽可能健壮。我仍然有点惊讶这不是内核内置的 - 看起来像一个明显的要求(当我打字时,我有三个类似于“闪光”的通知来自Stack Overflow(即新徽章,关联我的帐户等)。;) - Joshua Pinter
5
一个很好的答案。但是,有两个问题:flash.now 方法和在 redirect_to 调用中作为额外参数给出 flash 消息的可能性。第一个问题可以通过为 flash_message 方法提供第三个(可能是可选的)布尔参数来处理;如果将其值设置为 true,则该方法应该使用 flash.now 数组而不是 flash 的数组。(一个空数组的初始化就足够了。)第二个问题很简单,只需在调用 redirect_to 之前将闪现消息设置在单独的行上,而不是使用额外的参数即可解决。 - Teemu Leisti
1
我会使用这个作为flash_message的备用第一行,以确保它是一个数组。 flash[type] = *flash[type] - Alien Life Form
@TeemuLeisti 感谢您的 flash.now 建议。虽然在我的情况下,我发现将其初始化为空数组是 不够 的。如果为 true,我需要 flash.now[type] ||= [],如果为 false(即非 "now"),则需要 flash[type] ||= []。我正在使用 Rails 5.2。 - stwr667
3
@Victor 我强烈建议将 messages.each do |m| 调整为 Array.wrap(messages).each do |m|。这样可以使任何现有的闪存消息向后兼容,这对两个原因都很有帮助。1. 减少所有现有闪存消息的重构(只需要在需要多个消息时替换即可)。2. 它将确保添加闪存消息的任何 gem 不会引起异常,例如 DeviseAuthlogic,它们管理用户身份验证并常常添加闪存消息。 - stwr667
1
这里是一个总结。 - Backo

52

flash消息可以是任何你想要的东西,因此你可以这样做:

flash[:notice] = ["Message 1"]
flash[:notice] << "Message 2"

然后在您的视图中,将其输出为

<%= flash[:notice].join("<br>") %>

或者你喜欢的任何方式。

该技术是否比其他解决方案更简单,取决于你自己的喜好。


2
在Rails 3中,除非标记为安全,否则<br>将被转义。尝试使用safe_join<%= safe_join(flash[:notice], "<br>".html_safe) %>。还要注意,单个flash项目通常只是字符串。 mipadi在实例化周围使用[方括号]创建数组。没有这些括号,<<只会将更多文本附加到字符串中。 - Mark Berry
据我的了解,如果你执行 redirect_to path, notice: 'where is it gone?',它会被覆盖,所以这是一个需要小心处理的解决方案。 - Felix

5

我认为框架内置的思想是将每个信息都放入flash中并可以进行覆盖。您需要为每个消息分配一个唯一的键,以便可以更改或覆盖它。

如果您需要另一条消息,请不要将其命名为“:notice”。给每个消息命名独特的名称。然后循环遍历哈希表中的任何内容以呈现flash消息。

如果这对您没有效果,请考虑是否真的需要简化您的用户界面。


2

虽然我同意Jonathan的看法,认为用户界面可能需要一些简化,但有时您可能希望显示相同关键字的多个消息。

因此,我创建了一个宝石(gem),可以轻松处理相同关键字的多个闪存消息及其在视图中的呈现。

GitHub: flash-dance


1

以下是从答案及其后续评论中提取的摘要。

在app/helpers/application_helper.rb文件中添加以下内容:

module ApplicationHelper
  def flash_message(type, message, now = false)
    f = now ? flash.now : flash
    f[type] ||= []
    f[type] << message
  end

  def render_flash_messages
    rendered = []
    flash.each do |type, messages|
      Array.wrap(messages).each do |m|
        rendered << render(:partial => 'path/to/flash_messages', :locals => {:type => type, :message => m}) unless m.blank?
      end
    end
    rendered.join('<br/>')
  end
end

在控制器文件中:
class UsersController < ApplicationController
  def index
    helpers.flash_message(:success, "Some text")
  end
end

在视图文件中:
<%= sanitize(render_flash_messages) %>

缺点是,要在控制器中使用助手(Rails 5+),您必须使用 helpers对象,这可能是一个设计问题。它可能会引起一些麻烦。


1
在Rails 4.1上,这将不起作用。我有一个不同的实现,所以我认为你的代码应该改成这样:
def render_flash
  rendered = []
  flash.keys do |type|
    flash[type].each do |m|
      rendered << render(:partial => 'partials/flash', :locals => {:type => type, :message => m}) unless m.blank?
    end
  end
  rendered.join('<br/>')
end

2
flash[name] 应该改为 flash[type] 吗? - Joshua Pinter

0
如果您想要在您的应用程序中添加闪现消息,您只需要按照以下步骤进行操作:
添加一个名为 _flash_messages.html.erb 的文件,并在其中添加以下代码。
<% flash.each do |type, message| %>
  <div class="alert <%= bootstrap_class_for(type) %> fade in">
    <button class="close" data-dismiss="alert">×</button>
    <%= message %>
  </div>
<% end %>

现在在application.html.erb中调用它,就像在application.html.erb中添加这一行。
<%= render partial: "shared/flash_messages", flash: flash %> 

现在将以下代码添加到application.helper.rb文件中

module ApplicationHelper

def bootstrap_class_for flash_type
  case flash_type
    when :success
      "alert-success"
    when :error
      "alert-error"
    when :alert
      "alert-block"
    when :notice
      "alert-info"
    else
      flash_type.to_s
  end
end

结束

希望这对你有用。


0

使用 这个答案 作为灵感,以简单的方式一次执行多个闪存消息而不需要太多麻烦:

flash[:notice] = "#{flash[:notice]} Message 1<br />"
flash[:notice] = "#{flash[:notice]} Message 2"

或者

flash[:notice] = flash[:notice].to_s + 'Message 1<br />'
flash[:notice] = flash[:notice].to_s + 'Message 2'

引用上面提到的答案:

这个方法可行是因为 NilClass 定义了一个 #to_s 方法,它返回一个零长度的字符串,并且实例变量会自动初始化为 nil。

根据情况,虽然不在本篇问题的上下文中,但你可能需要处理尾随的换行标签、逗号或任何你使用的“分隔符”。你可以使用多种方法来处理,比如 chomp


0
一种使用“传统”的单行消息和带有换行符的数组样式消息的方法。
在Rails 4.1和JSON序列化器中,您可以使用单行闪存消息。
flash[:notice] = 'message'

以及多行闪现消息

flash[:notice] = ['message line 1', 'message line 2']

像这样(在application.html.haml或适当的模板文件中)

- if notice
   #css_class 
   = safe_join(Array(notice), '<br/>'.html_safe)

0

Bootstap 4,纤巧

.container.mt-3.full-max-width-down-md
  - flash.each do |key, value|
    div{class="alert alert-#{key} alert-dismissible fade show text-center" role="alert"}
      button type="button" class="close" data-dismiss="alert" aria-label="Close"
        i class="fa fa-times" aria-hidden="true"

      - if value.is_a? Array
        = safe_join(value, "<br />".html_safe)
      - else
        = value

例子

flash[:notice] = "Hey"
flash[:notice] = ["Hey", "Hey"]
redirect_to my_path, flash: { notice: "Hey" }
redirect_to my_path, flash: { notice: ["Hey", "Hey"] }

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