Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to stay DRY when using both Javascript and ERB templates (Rails)

I'm building a Rails app that uses Pusher to use web sockets to push updates to directly to the client. In javascript:

channel.bind('tweet-create', function(tweet){ //when a tweet is created, execute the following code:
  $('#timeline').append("<div class='tweet'><div class='tweeter'>"+tweet.username+"</div>"+tweet.status+"</div>");
});

This is nasty mixing of code and presentation. So the natural solution would be to use a javascript template. Perhaps eco or mustache:

//store this somewhere convenient, perhaps in the view folder:
tweet_view = "<div class='tweet'><div class='tweeter'>{{tweet.username}}</div>{{tweet.status}}</div>"

channel.bind('tweet-create', function(tweet){ //when a tweet is created, execute the following code:
    $('#timeline').append(Mustache.to_html(tweet_view, tweet)); //much cleaner
});

This is good and all, except, I'm repeating myself. The mustache template is 99% identical to the ERB templates I already have written to render HTML from the server. The intended output/purpose of the mustache and ERB templates are 100% the same: to turn a tweet object into tweet html.

What is the best way to eliminate this repetition?

UPDATE: Even though I answered my own question, I really want to see other ideas/solutions from other people--hence the bounty!

like image 559
user94154 Avatar asked Feb 25 '11 19:02

user94154


1 Answers

imo the easiest way to do this would involve using AJAX to update the page when a new tweet is created. This would require creating two files, the first being a standard html.erb file and the second being a js.erb file. The html.erb will be the standard form which can iterate through and display all the tweets after they are pulled from the database. The js.erb file will be your simple javascript to append a new tweet upon creation, i.e.:

$('#timeline').append("<div class='tweet'><div class='tweeter'><%= tweet.username %></div><%= tweet.status %></div>")

In your form for the new tweet you would need to add:

:remote => true

which will enable AJAX. Then in the create action you need to add code like this:

def create
...Processing logic...
  respond_to do |format|
    format.html { redirect_to tweets_path }
    format.js
  end
end

In this instance, if you post a tweet with an AJAX enabled form, it would respond to the call by running whatever code is in create.js.erb (which would be the $('#timeline').append code from above). Otherwise it will redirect to wherever you want to send it (in this case 'Index' for tweets). This is imo the DRYest and clearest way to accomplish what you are trying to do.

like image 62
Will Ayd Avatar answered Sep 20 '22 13:09

Will Ayd