使用ReactJS调用AJAX后处理Rails flash消息

rdn*_*man 4 javascript ajax ruby-on-rails reactjs

有几篇帖子描述了在AJAX调用之后显示flash消息(例如,在ajax调用之后Rails不显示flash消息,你如何使用Ajax请求处理Rail的flash?).

我正在使用带有react-rails的ReactJS并希望这样做,并希望利用React的动态显示渲染.

因此,我正在回答我自己的问题,即如何在AJAX调用之后使用下面的ReactJS来回复Flash消息,以回答可能遇到此问题的其他人并获得改进建议.

rdn*_*man 6

该实施主要基于该主题的其他SO帖子(参见相关参考文献).该代码假设Rails 4.x包含资产管道,HAML用于视图,Bootstrap用于样式,以及使用react-rails gem.

(更新:稍微长一点的讨论可以在我的博客上找到).

布局
这是app/views/layouts/application.html.haml文件:

!!!
%html
  %head
    %title
      Demo

    = stylesheet_link_tag    'application', media: 'all', 'data-turbolinks-track' => true
    = javascript_include_tag 'application', 'data-turbolinks-track' => true
    = csrf_meta_tags

  %body
    %div.container
      %div#flash_messages
      = yield
Run Code Online (Sandbox Code Playgroud)

请注意,其divid为#flash_messages.此容器div的放置确定了闪存消息的显示位置.

控制器
下面的私有例程简单地将本机数组的使用转换为标头中的可解析JSON.

class ApplicationController < ActionController::Base
  protect_from_forgery with: :exception
  after_filter :flash_to_http_header

private
  def flash_to_http_header
    return unless request.xhr?
    return if flash.empty?
    response.headers['X-FlashMessages'] = flash.to_hash.to_json
    flash.discard  # don't want the flash to appear when you reload page
  end
end
Run Code Online (Sandbox Code Playgroud)

Javascript(ReactJS)
以下javascript由React类,用于处理响应头中的flash消息的全局函数以及用于完成AJAX调用的JQuery处理程序组成.它被放入一个JX文件(我用过app/assets/javascripts/react/flash_messages.js.jsx)中,以保持相关的JS功能.我在下面讨论这个.

/** @jsx React.DOM */

var FlashMessages = React.createClass({
  getInitialState: function() {
    return {messages: this.props.messages};
  },

  messages: function (messageArray) {
    this.replaceState({messages: messageArray});
  },

  render: function() {
    return (
      <div className='flash_messages_component'>
        {this.state.messages.map(function(message, index) {
          _level = message[0];
          _text  = message[1];
          return (
            <div key={index} className={this._flash_class(_level)}>
              {_text}
            </div>
          );
        }.bind(this))}
      </div>
    )
  },

  _flash_class: function(level) {
    var _result = 'alert alert-error';
    if (level === 'notice') {
      _result = 'alert alert-info';
    } else if (level === 'success') {
      _result = 'alert alert-success';
    } else if (level === 'error') {
      _result = 'alert alert-error';
    } else if (level === 'alert') {
      _result = 'alert alert-error';
    }
    return _result;
  }

});

function handleFlashMessagesHeader(node, xhr) {
  var _message_array = new Array();
  var _raw_messages = xhr.getResponseHeader("X-FlashMessages")
  if (_raw_messages) {
    var _json_messages = JSON.parse(_raw_messages);
    count = 0
    for (var key in _json_messages) {
      _message_array[count] = new Array();
      _message_array[count][0] = key;
      _message_array[count][1] = _json_messages[key];
      count += 1;
    }
  }
  node.messages(_message_array);
}

$(document).ready(function() {
  var dummy = new Array();
  var flashDiv = React.render(<FlashMessages messages={dummy} />, $('#flash_messages')[0]);

  $(document).ajaxComplete(function(event, xhr, settings) {
    handleFlashMessagesHeader(flashDiv, xhr);
  });
});
Run Code Online (Sandbox Code Playgroud)

FlashMessages阵营类做了几件事情.首先,它将道具移动到状态.通常这将是一个反模式,但这样做可以使非React代码在需要时触发更改.该messages函数是触发器,意味着由外部JS代码调用.render假设Rails flash-native-of-2-element-arrays数据结构的主要处理是将处理保持在最小程度,并允许直接从视图中使用组件而不仅仅是AJAX调用.最后,本地_flash_class方法支持Bootstrap样式(当然可以根据需要调整其他样式).

handleFlashMessagesHeader是一个全局函数,用于将JSON转换回由Rails控制器过滤器方法完成的数组数组.请注意,它从Rails应用程序视图/布局中获取带有id标记的DOM元素.

最后一节是为了在页面加载时运行,因此依赖于JQuery就绪.在React.render(正式React.renderComponent)被保存到一个全局变量,允许直接调用到FlashMessages对象的message方法(dummy使用数组只是播种空闪烁数组首先被调用的时候-这也许可以过一个空试验作出反应类中处理) .每当ajaxComplete触发时,handleFlashMessageHeader都会调用该函数并传递React对象以进行更新.

非AJAX
因为React类假定本机数组,所以视图可以简单地调用a

= react-component 'FlashMessages', flash, :div
Run Code Online (Sandbox Code Playgroud)

而是显示它,但当然它不太有用,因为不支持动态响应.但是,以某种方式调用它的能力为某些用例提供了更大的灵活性.