繁体   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