开发者

Can I use JS conditions in my Rails 3 js.erb file to render partials?

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开发者_JAVA技巧 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


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.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜