需要一种方法让Rails控制器返回flash消息以响应AJAX请求

时间:2014-02-02 19:32:53

标签: ajax ruby-on-rails-4

作为一个经验不足但快速学习的Rails开发人员,我想编写一个控制器后过滤器来检查AJAX请求,并在自定义标头中返回一些HTML,响应处理程序可以使用它来显示任何flash消息。

为了保持DRY的一致性和一致性,我想使用Rails生成的相同app / views / layouts / _messages.html.erb(.haml)来创建部分HTML。

在查看了几个帖子之后,我的解决方案是:

  # adapted from http://stackoverflow.com/a/2729454/270511
  def flash_to_headers
    return unless request.xhr?
    response.headers['X-flash'] = render_to_string partial: 'layouts/messages.html'
    flash.discard  # don't want the flash to appear when you reload page
  end

这实际上会返回所需的标题,但也会throws an exception

后续搜索显示几个帖子,其中受访者声称不支持从后过滤器调用render_to_string。

我想到的另一个解决方案是第二次从views / layouts / application.html.haml渲染layouts / navigation.html,但是在div中包含display = none。要使用相同的模板完成此操作,我将不得不向flash [:notice,:warn和:error]添加一些虚假的占位符消息,因为否则_messages.html.haml写入时不会在没有相关的情况下呈现部分消息。然后我可以使用占位符作为模板来克隆并填写后续AJAX请求返回的flash消息。

虽然这可能有用,但我觉得它很难看并且有难闻的气味。 (我对Rails缺乏经验,但没有进行软件开发!)由于我缺乏Rails经验(以及缺乏可用的导师),我可能错过了一些东西。如果是这样,如果有人可以指出一种更清洁的方式来实现我的目标,我将不胜感激。

如果没有,我会将此重新发布到Github上的rails问题列表中。我认为显示flash消息以指示从最终用户的AJAX请求的一些反馈是一个常见的用例Rails应该更好地支持它。

1 个答案:

答案 0 :(得分:0)

我认为我的AJAX请求是API调用,因此我只在我的邮件头中发送最少的信息,并且只发送最相关的错误消息

application_controller.rb

return unless request.xhr?

if type = priority_flash # Method that returns most relevant message
  response.headers['X-Message'] = flash[type]
  response.headers['X-Message-Type'] = type.to_s

  flash.discard  # don't want the flash to appear when you reload page  
end

呈现错误消息的工作应该属于javascript文件

some_js_file.js

// AJAX callbacks
$(document).ajaxComplete(function(e, request, opts) { 
    fireFlash(request.getResponseHeader('X-Message'), request.getResponseHeader('X-Message-Type')); 
});

$(document).ajaxError(function(event, jqxhr, settings, thrownError){
    fireFlash("AJAX request failed : " + jqxhr.status + " "+thrownError, "danger")
});

/* AJAX Flash messages */
function fireFlash(content, type){
    if (content === null){
        return
    }
    var alert_type;
    switch(type){
        case "alert":
        case "danger":
        case "fatal":
        case "error":
            alert_type= "danger"
            break;
        case "success":
        case "notice":
            alert_type= "success"
            break;
        case "warning":
            alert_type= "warning"
        default:
            alert_type= "info"
    }
    $("#flashes").prepend($("<div/>")
        .addClass("alert alert-dismissible alert-ajax alert-"+alert_type)
        .html((decodeURIComponent(escape(content))))
        .append('<button type="button" class="close" data-dismiss="alert"><span aria-hidden="true">&times;</span><span class="sr-only">Close</span></button>')
    )
    document.location.href = "#top";
}