我可以在 Rails 3 js.erb 文件中使用 JS 条件来渲染部分内容吗?

发布于 2024-11-18 23:42:18 字数 2108 浏览 4 评论 0原文

抱歉,如果这有点复杂。我会尽力描述它,但如果我不清楚,请提问。

我正在开发一个需要自动更新状态页面的 Rails 应用程序。这个状态页面将有请求,其中有许多尝试,其中有许多步骤。为了尽可能保持此页面最新,我们使用 JQuery 每 5 秒轮询一次服务器。

然后,这将通过索引操作将我们带到index.js.erb 文件。该文件当前设置为确定(根据屏幕上的内容)需要重新渲染哪些部分。我使用屏幕上当前的内容来确定请求/尝试/步骤是否仍然处于活动状态,以了解需要刷新的内容。我选择了这个,而不是使用数据库中的内容,因为数据库会将项目更新为非活动状态,导致屏幕上的活动项目不会更新以显示其新的非活动状态......但也许有更好的方法这。

现在谈谈我的主要问题。在我的 erb 文件中,我有很多:

if (some statements) {<%= escape_javascript(render :partial=>"my_partial") %>}

其中,评估中提到的所有部分脚本,无论什么条件。这将成倍地增加我们的渲染时间,并且似乎对我们的服务器造成了很大的打击。

有没有一种方法可以根据屏幕上当前的内容有条件地渲染部分内容?

有没有更好的方法来应对这整个考验?我知道动态更新的状态页面到处都是,但找不到一个很好的例子来引导我走向正确的方向。

另外,这是我的一些实际代码的片段,也许可以为我正在做的事情提供更好的示例。我对复杂的 javascript 还很陌生,所以如果我有什么完全不对劲的地方,请告诉我。

<%attempt.steps.each do |step|  %>
        /* If  a status for this step already exists on the page, only update portions of it, otherwise append the step status to the page */      
        if (document.getElementById("step-status-<%= step.id %>")) {
            $("#step-status-<%= step.id %>").html('<%= escape_javascript(render :partial=>'step_status', :locals=>{:step=>step}) %>');
        <% if step.log.present? #log will be present once step is complete %>
            /* If the log isn't displayed on the page, add the partial to display it. This is supposed to allow for this partial to only be rendered once and not refreshed*/ 
            if ($("#step-<%= step.id %>-log pre").is(":empty")) {
                $("#step-<%= step.id %>-log").html('<%= escape_javascript(render :partial=>'log_details', :locals=>{:step=>step}) %>');
                $("#step-<%= step.id %>-log-button").html('<%= escape_javascript(link_to("View Log", "#", :id=>"step-#{step.id}")) %>');
            }
        <% end %>
        } else {
            $("#step-details-list-<%= attempt.id %>").append('<%= escape_javascript(render :partial=>"step", :locals=>{:step=>step}) %>');
        }
    <% end  %>

非常感谢您的帮助。

崔西

Sorry if this is a bit complicated. I will try to describe it as best I can, but please ask questions if I am unclear.

I am working on a Rails app that needs to have an auto-updated status page. This status page will have Requests, which have many Attempts, which have many Steps. In order to keep this page as current as reasonably possible, we are using JQuery to poll the server every 5 seconds.

This then brings us to the index.js.erb file via the index action. This file is currently set up to determine (based on what's on the screen) which partials need to be re-rendered. I use what's currently on the screen to determine if a request/attempt/step is still active to know what needs to be refreshed. I chose this, instead of using what's in the database, since the database would update an item to be inactive, causing the onscreen, active item to not be updated to show it's new inactive status.... but maybe there's a better way around this.

Now to my main issue. In my erb file, I have plenty of:

if (some statement) {<%= escape_javascript(render :partial=>"my_partial") %>}

which, evaluates all partials mentioned in the script, no matter what condition. This is going to increase our rendering time exponentially, and seems to be taking a big hit on our server.

Is there a way to conditionally render partials based upon what's currently on the screen?

Is there a way better approach to this whole ordeal? I know dynamically updated status pages are all over the place, but could not find a good example to lead me in the right direction.

Also, here's a snippet of some of my actual code, to maybe provide a better example of what I'm doing. I'm fairly new to complex javascript, so please let me know if I have something completely out of sorts.

<%attempt.steps.each do |step|  %>
        /* If  a status for this step already exists on the page, only update portions of it, otherwise append the step status to the page */      
        if (document.getElementById("step-status-<%= step.id %>")) {
            $("#step-status-<%= step.id %>").html('<%= escape_javascript(render :partial=>'step_status', :locals=>{:step=>step}) %>');
        <% if step.log.present? #log will be present once step is complete %>
            /* If the log isn't displayed on the page, add the partial to display it. This is supposed to allow for this partial to only be rendered once and not refreshed*/ 
            if ($("#step-<%= step.id %>-log pre").is(":empty")) {
                $("#step-<%= step.id %>-log").html('<%= escape_javascript(render :partial=>'log_details', :locals=>{:step=>step}) %>');
                $("#step-<%= step.id %>-log-button").html('<%= escape_javascript(link_to("View Log", "#", :id=>"step-#{step.id}")) %>');
            }
        <% end %>
        } else {
            $("#step-details-list-<%= attempt.id %>").append('<%= escape_javascript(render :partial=>"step", :locals=>{:step=>step}) %>');
        }
    <% end  %>

Thank you so much for any help.

Trish

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

月寒剑心 2024-11-25 23:42:18

考虑向您的客户端引入“last_updated_at”的概念。

在您的控制器中:

def index
  # Lets pretend the earliest you're interested in is 1 day ago
  updated_since = params[:last_updated_at].try(:to_time) || 1.day.ago 

  # For ease, i'm doing the query here; this query may be more appropriate as a scope in the model
  @steps = Steps.where(["updated_at > ?", updated_since]) 
end

在您的 index.js.erb 视图中:

<% @steps.each do |step| %>
  var step_html = '<%= escape_javascript(render :partial=>'log_details', :locals=>{:step=>step}) %>';
  var step_ele = $('#step-<%= step.id %>')[0];
  if (step_ele) {
    // Step was already in the page; just replace it
    step_ele.html(step_html);
  }
  else {
    // Step isn't on the page yet; append it to its container
    $('#step-container').append(step_html);
  }
<% end %>
window.last_updated_at = "<%= Time.now.to_s %>";

也对您的 Request 和 Attempts 模型执行此操作。

在更新代码中,将 last_updated_at 查询字符串附加到更新网址,因此它类似于 'http://stats.example.com/index.js?last_updated_at=' + window.last_updated_at

另外:请注意命名模型 Request; Rails 中已经有一个 Request 类,你可能会遇到冲突。

Consider introducing the notion of "last_updated_at" to your client side.

In your controller:

def index
  # Lets pretend the earliest you're interested in is 1 day ago
  updated_since = params[:last_updated_at].try(:to_time) || 1.day.ago 

  # For ease, i'm doing the query here; this query may be more appropriate as a scope in the model
  @steps = Steps.where(["updated_at > ?", updated_since]) 
end

In your index.js.erb view:

<% @steps.each do |step| %>
  var step_html = '<%= escape_javascript(render :partial=>'log_details', :locals=>{:step=>step}) %>';
  var step_ele = $('#step-<%= step.id %>')[0];
  if (step_ele) {
    // Step was already in the page; just replace it
    step_ele.html(step_html);
  }
  else {
    // Step isn't on the page yet; append it to its container
    $('#step-container').append(step_html);
  }
<% end %>
window.last_updated_at = "<%= Time.now.to_s %>";

Do this for your Request and Attempts models as well.

In your updating code, append the last_updated_at query string to to the updating url, so it is something like 'http://stats.example.com/index.js?last_updated_at=' + window.last_updated_at.

Aside: beware of naming your model Request; there is already a Request class in rails, and you may run into conflicts.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文