简体   繁体   中英

Refresh a div frequently without page refresh in rails

I have a rails application that shows my system's CPU usages, total Memory, Uptime etc. details.

I want it to update the fields every 0.25 seconds using AJAX. My index_controller.rb has this line:

class IndexController < ApplicationController
    def system_stats
    end
end

system_stats.html.erb:

<div class="centrify mb-4">
    <div class="logo">
        <svg class="pi-anim" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512"><path fill="#00c1fd" d="M256 512A254 254 0 010 256 254 254 0 01256 0a254 254 0 01256 256 254 254 0 01-256 256z" data-original="#00C1FD"/><path fill="#08a8ee" d="M437 75C389 27 324 0 256 0v512a254 254 0 00256-256c0-68-27-133-75-181z" data-original="#08A8EE"/><g fill="#e4f7ff"><path class="info-i" d="M301 371V221H191v30h20v120h-21v30h130v-30zM256 191a45 45 0 100-90 45 45 0 000 90z" data-original="#E4F7FF"/></g><path class="info-i2" fill="#cbedfd" d="M256 191a45 45 0 000-90v90zM301 371V221h-45v180h64v-30z" class="active-path" data-old_color="#CBEDFD" data-original="#CBEDFD"/></svg>
    </div>

    <h1>System Stats</h1>
</div>

<% if Rails.env.production? %>
    <div class="centrify"><h6>Warning! On a Production Server this could mean nothing</h6></div>
    <hr>
<% end %>

<h4>Processor</h4>
<%= processor[0] %>
<%= "[ #{processor[1]} ]" %>
<hr>

<h4>CPU Usages</h4>
<%= %Q[#{cpu_usage.then { |x| "Total: #{x[0]}<br>[#{x.drop(1).join(', ')}]" }}].html_safe %>
<hr>

<h4>Memory</h4>
<%= "Total: #{memory} GiB" %>
<hr>

<h4>Uptime</h4>
<div id="uptime"><%= render 'stats/uptime', remote: true %></div>
<hr>

stats/_uptime.html.erb:

<%= "Uptime: #{uptime.map { |x| x.then { |y| y < 10 ? "0#{y}" : "#{y}" }}.join(?:)}" %>

index_helper.rb:

module IndexHelper
    def processor
        if File.readable?('/proc/cpuinfo')
            cpuinfo = IO.readlines('/proc/cpuinfo')
            model = cpuinfo.select { |x| x[/\Amodel\sname/] }
            [model[0].split(?:)[1].strip, model.count]
        else
            []
        end
    end

    def cpu_usage
        if File.readable?('/proc/stat')
            data = IO.readlines('/proc/stat').select! { |x| x[/^cpu\d*/] }.map! { |x| x.split.map!(&:to_f) }
            Kernel.sleep(0.075)
            prev_data = IO.readlines('/proc/stat').select! { |x| x[/^cpu\d*/] }.map! { |x| x.split.map!(&:to_f) }

            data.size.times.map do |x|
                %w(user nice sys idle iowait irq softirq steal).each_with_index { |el, ind| binding.eval("@#{el}, @prev_#{el} = #{data[x][ind + 1]}, #{prev_data[x][ind + 1]}") }

                previdle, idle = @prev_idle + @prev_iowait, @idle + @iowait
                totald = idle + (@user + @nice + @sys + @irq + @softirq + @steal) -
                    (previdle + (@prev_user + @prev_nice + @prev_sys + @prev_irq + @prev_softirq + @prev_steal))
                "#{((totald - (idle - previdle)) / totald * 100).round( x == 0 ? 2 : 0 ).then { |y| y.to_s == 'NaN' ? 0 : y }.abs}%"
            end
        else
            ''
        end
    end

    def memory
        if File.readable?('/proc/meminfo')
            meminfo = IO.readlines('/proc/meminfo')
            meminfo.find { |x| x[/^MemTotal/] }.split[1].to_i.fdiv(1024 ** 2).round(2)
        else
            0
        end
    end

    def uptime
        if File.readable?('/proc/uptime')
            uptime = IO.read('/proc/uptime').split[0].to_i
            [uptime / 3600, uptime % 3600 / 60, uptime % 60]
        else
            []
        end
    end
end

This works, but just for simplicity say I want to update the uptime div every 0.25 seconds, what's the way to do that? I have JQuery installed and running.

Create a function to do an AJAX request every 0.25 seconds:

function updateSystemInfo() {
  setInterval(function(){ 
    Rails.ajax({
      url: "/system_stats",
      type: "get",
      dataType: "script"
    });
 }, 0250);
}

Now your controller wants to respond to the JS request and will look for a system_stats.js.erb file. In that file you can tell rails to update the part of the view you want to update.

Now you can put the following part into a partial _system_stats.html.erb :

<h4>Processor</h4>
<%= processor[0] %>
<%= "[ #{processor[1]} ]" %>
<hr>

<h4>CPU Usages</h4>
<%= %Q[#{cpu_usage.then { |x| "Total: #{x[0]}<br>[#{x.drop(1).join(', ')}]" }}].html_safe %>
<hr>

<h4>Memory</h4>
<%= "Total: #{memory} GiB" %>
<hr>

And on the system_stats.html.erb you place an empty div with an ID, for example <div id="system_stats"></div>

Now in the system_stats.js.erb you tell rails to render the partial in the div with ID system_stats.

$("#system_stats").html("#{escape_javascript(render 'system_stats')}");

Now every 0.25 seconds the partial will be rerenderd.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM