簡體   English   中英

如何在使用Javascript和ERB模板(Rails)時保持DRY

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

我正在構建一個Rails應用程序,它使用Pusher來使用Web套接字將更新直接推送到客戶端。 在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>");
});

這是令人討厭的代碼和演示混合。 所以自然的解決方案是使用javascript模板。 也許生態或胡子:

//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
});

這很好,除了我重復自己 胡子模板與我已編寫的用於從服務器呈現HTML的ERB模板99%相同。 胡子和ERB模板的預期輸出/目的是100%相同:將tweet對象轉換為tweet html。

消除這種重復的最佳方法是什么?

更新:即使我回答了我自己的問題,我真的希望看到其他人的其他想法/解決方案 - 因此是賞金!

imo最簡單的方法是在創建新推文時使用AJAX更新頁面。 這需要創建兩個文件,第一個是標准的html.erb文件,第二個是js.erb文件。 html.erb將是標准表單,它可以迭代並顯示從數據庫中提取后的所有推文。 js.erb文件將是您在創建時附加新推文的簡單javascript,即:

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

在您的新推文的表單中,您需要添加:

:remote => true

這將啟用AJAX。 然后在創建操作中,您需要添加如下代碼:

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

在這種情況下,如果你發布一個啟用了AJAX形式的推文,它會通過運行create.js.erb中的任何代碼來響應調用(這將是$('#timeline')。來自上面的代碼) 。 否則它將重定向到您想要發送它的任何地方(在這種情況下,推文的“索引”)。 這是實現你想要做的最干凈,最清晰的方式。

到目前為止,我找到的最佳解決方案是同位素

它允許您使用Javascript編寫模板,Javascript可以由客戶端和服務器呈現。

我會使用Javascript渲染所有推文。 不是在服務器上呈現HTML,而是在頁面的頭部將初始數據設置為JS。 頁面加載時,使用JS呈現推文。

在你的頭腦中:

%head
  :javascript
    window.existingTweets = [{'status' : 'my tweet', 'username' : 'glasner'}];

在JS文件中:

$.fn.timeline = function() {
  this.extend({
    template: "<div class='tweet'><div class='tweeter'>{{tweet.username}}</div>{{tweet.status}}</div>",
    push: function(hash){
      // have to refer to timeline with global variable
      var tweet = Mustache.to_html(timeline.template, hash)     
      timeline.append(tweet);
    }
  });  

  window.timeline = this;

  channel.bind('tweet-create', this.push);  

  // I use Underscore, but you can loop through however you want
  _.each(existingTweets,function(hash) {
    timeline.push(hash);
  });

  return this
};  


$(document).ready(function() {
  $('#timeline').timeline();
});

我沒試過這個,但這只是我想到的一個可能的解決方案:

在您的視圖中創建一個隱藏的div,其中包含一個示例模板(為簡潔起見,我在這里使用HAML):

#tweet-prototype{:style => "display:none"}
    = render :partial => Tweet.prototype

您的推文部分可以像現在一樣呈現推文。

.tweet
    .tweeter
        = tweet.username
    .status
        = tweet.status

在創建推文原型時,你可以將你想要的字段設置為js-template替換語法,你絕對可以把它干掉,但是我在這里完整地包含它作為示例目的。

# tweet.rb
def self.prototype
    Tweet.new{:username => "${tweet.username}", :status => "${tweet.status}"}
end

在客戶端,您可以執行以下操作:

var template = new Template($('#tweet-prototype').html());
template.evaluate(.. your tweet json..);

最后一部分將取決於你如何做你的模板,但它就是這樣的。

如前所述,我沒有嘗試過這種技術,並且它不會讓你直接在模板中做循環或條件格式化之類的東西,但你可以用一些創造力來解決這個問題,我敢肯定。

這與你使用同位素所要做的事情相去甚遠,並且在許多方面都是劣等的,但它絕對是一個更簡單的解決方案。 我個人喜歡haml,盡可能多地寫下我的標記,所以這對我個人來說是一個更好的解決方案。

我希望這有幫助!

為了能夠使用胡子模板在javascript和rails之間共享模板,有smt_rails: https//github.com/railsware/smt_rails (“rails 3的共享胡子模板”)以及Poirot: https:// github .com / olivernn / poirot

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM