【问题标题】:Rails 4 live streaming updates to a bootstrap table row updated with in-place editingRails 4 对引导表行的实时流式更新,通过就地编辑进行了更新
【发布时间】:2014-11-24 19:29:30
【问题描述】:

虽然我可能已经为这个网站上的每个问题添加了书签,但我几乎从不发布我自己的问题,因为我害怕一个尖刻的回答。所以,如果我忽略了一些完全明显的事情或者只是以错误的方式处理这个问题,请提前道歉,但是我已经到了互联网的尽头,我的脑袋正在转动,所以我呼吁 Rails 社区的增援。

如果有任何关于在我的 Rails 4 应用程序中不断刷新数据表中行的好方法的建议,我将不胜感激。

我最初试图解决的问题是我的同事需要同时访问每月生成的 Excel 文档。我非常不喜欢 Excel,所以我在 Rails 4 应用程序中创建了这些文档的更好版本,我的同事现在可以同时编辑它。

我目前正在尝试解决的问题是他们需要实时查看彼此的更新。表格单元格由我的同事(最多 40 个同时用户)在我公司的内部 web 应用程序上更新。 (Google 电子表格不是一个可行的解决方案,因为数据是相关的,并且在 mySql 数据库中维护得更好。)

这是我的第一个 Rails 应用程序之一,但自 Hello World 以来它已经走过了漫长的道路。在当前状态下,我使用 Rails 4.1.6 和 JQuery dataTables 结合 best_in_place gem 进行就地编辑。

该应用程序目前运行良好,但我不断收到有关在同一行的其他单元格中输入新数据时依赖单元格未更新的电子邮件(我的同事习惯于他们的数据采用 Excel 格式并立即看到一个单元格更新基于任何公式)。我厌倦了(并且真的很尴尬)告诉他们“刷新页面”来解决他们的问题。此外,我希望每个人都能实时看到更新。

我已经尝试过sync gem(使用 Faye 和 Thin),但我终其一生都无法让它在任何环境中工作,而且实际上只有两个教程(sync_exampleRailsConf video with no code),两者都没有解释如何在生产环境中实现它。

我目前通过TenderLove's Is it live? blog post 的 ActionController::Live(使用 Puma 和 Nginx)使用服务器发送的事件/事件源。这种方法的问题是,在客户端断开连接或导航到另一个页面后,我无法关闭连接,因此我的所有数据库连接都被用完,然后数据库连接被阻止。 This seems to be a known issue for many others 但我想知道我是不是完全走错了路。

不断循环会不会是个问题?如果我把它改回n.times,我会不会失去连接并回到第一格??

这是我的代码。 #products 是我的 jQuery 数据表,每一行都以具有唯一 ID 的部分呈现。

在我的产品/展示视图中:

         <tbody>
            <% @products.each do |product| %>
              <%= render partial: '/products/product', :collection => @products %>    
            <% end %>
          </tbody>
        </table>
. . .
<script type='text/javascript'>

jQuery(document).ready(function() {
    setTimeout(function() {
      var source = new EventSource('/application/events');
      source.addEventListener('refresh_product_row', function(event) {
        var id = JSON.parse(event.data).id;
        $.getScript('/products/show.js?id=' + id);
        $('#products').dataTable();
      });
    }, 1);
  });

</script>

show.js.erb

$('#products tbody #product_row_<%= @product.id %>').hide();
$('#products tbody #product_row_<%= @product.id %>').replaceWith('<%= escape_javascript(raw render(:partial => "products/product", :object => @product))%>');
$('#products tbody #product_row_<%= @product.id %>').fadeIn('slow');
// Re-activating Best In Place
$('.best_in_place').best_in_place();

在我的应用程序控制器中:

def events
  unless ENV['RAILS_ENV'] == 'development'
    # SSE expects the `text/event-stream` content type
    response.headers['Content-Type'] = 'text/event-stream'

    sse = Reloader::SSE.new(response.stream)
    start = Time.zone.now

    begin
      # 10.times do
      loop do
        Product.uncached do
          Product.where('updated_at > ?', start).each do |product|
            # data will be streamed to the client every time we call the write method.
            sse.write({ :id => product.id }, :event => 'refresh_product_row')
            sleep 0.0001
            start = product.updated_at
          end
        end
        sleep 1
      end
      render nothing: true
    rescue IOError
      # When the client disconnects, we'll get an IOError on write
      logger.info "Client disconnected. Stream closed"
    ensure
      sse.close
    end
  end
end

在 /lib/reloader/sse.rb 中

require 'json'

module Reloader
  class SSE
    def initialize io
      @io = io
    end

    def write object, options = {}
      options.each do |k,v|
        @io.write "#{k}: #{v}\n"
      end
      @io.write "data: #{JSON.dump(object)}\n\n"
    end

    def close
      @io.close
    end
  end
end

如果您需要更多信息,请告诉我。谢谢!!

【问题讨论】:

    标签: ruby-on-rails-4 synchronization datatables server-sent-events best-in-place


    【解决方案1】:

    这里有很多代码要粘贴,所以检查一下这段代码,我只是粘贴我的表格代码,其余的你按照教程做 https://melvinchng.github.io/rails/ActionCable.html#21-initial-setup

    index.html.erb

    <h1>All Leaderboard Entries</h1> 
       <div class='container-fluid'> 
          <div class='row py-3 px-3'>
            <div class='col-12 col-sm-8'> 
              <table id='entry-table' class="table table-hover">
                <thead  class="thead-light">
                  <tr>
                    <th>Leaderboard</th>
                    <th>Username</th>
                    <th>Score</th>
                    <th colspan="3"></th>
                  </tr>
                </thead> 
              <tbody id="leaderboard_entries"> 
                 <%= render @leaderboard_entries.presence || 'leaderboard_entry' %> 
              </tbody>
            </table>
            </div>
           </div>
          </div>
    

    _leaderboard_entries.html.erb

      <tr>
        <td><%= leaderboard_entry.leaderboard.name%></td>
        <td><%= leaderboard_entry.username %></td>
        <td><%= leaderboard_entry.score %></td>
        <td><%= link_to '<i class="fa fa-eye" style="color:blue"></i> Show '.html_safe, leaderboard_entry %></td>
        <td><%= link_to '<i class="fa fa-edit" style="color:orange"></i> Edit '.html_safe, edit_leaderboard_entry_path(leaderboard_entry,  :return_to=>"leaderboard_entries") %></td>
        <td><%= link_to '<i class="fa fa-trash" style="color:red"></i> Destroy'.html_safe, leaderboard_entry, method: :delete, data: { confirm: 'Are you sure?' } %></td>
        </tr>
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2012-03-08
      • 2010-09-19
      • 1970-01-01
      • 1970-01-01
      • 2017-05-08
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多