ruby-on-rails - 一个 View 中有多个类似的循环,更好的做法吗?

标签 ruby-on-rails

使用 Rails 3。我的观点有 2 个选项:

选项A:

<% @items.each do |item| %>
  ...
<% end %>
...

<script>
  var items = [
    <% @items.each do |item| %>
      ['<%= item.name %>', <%= item.lat %>, <%= item.lng %>],
    <% end %>
  ];
</script>

选项B:

<% @items.each do |item| %>
  ...
  <% content_for :items_array do %>
    ['<%= item.name %>', <%= item.lat %>, <%= item.lng %>],
  <% end %>
<% end %>
...

<script>
  var items = [<%= yield :items_array %>];
</script>

目前,我选择了选项B,但我仍然认为它一点也不简洁。有更好的方法来做到这一点吗?我拒绝选择选项 A,因为由于性能和 DRY 问题,我不希望它在同一 View 中循环两次,如果我错了,请纠正我。

谢谢。

最佳答案

如果这是我的项目,我可能会将这个问题转移到 javascript 方面。将纬度和经度放入项目标签中某处的数据属性中,并使用不显眼的脚本来读取它们。 (如果您想要一个示例,请告诉我。)

如果这是不可能的,我个人更喜欢选项 A,首先是为了可读性(它更容易理解,特别是如果你不熟悉 content_for),其次是因为它更容易重构,我们可以转移收集数据进入模型的方法或者可能进入助手。 DRY 在这里并不适用,因为即使您循环访问相同的数据集,您也会用它做非常不同的事情。

也就是说,我不太确定性能影响,因此我进行了一些测试。我在我的一个应用程序中获取了 500 条客户记录,并使用选项 A 呈现链接列表,然后将其数据映射到 content_for block 中,并使用 Ruby 的内置 Benchmark 模块对其进行基准测试(它在 haml 而不是 erb 中,但我确信阅读起来并不太难。)

- bench = Benchmark.measure do
  %ul#client-list
    - @clients.each do |client|
      %li
        = link_to client.company, client
        - content_for :foobar do
          = "['#{j client.name}', '#{j client.company}', '#{j client.email}'],"

  = javascript_tag do
    var nearbys = [#{yield :foobar}];

%p= bench.to_s

结果,大约370毫秒

 0.370000 0.000000 0.370000 ( 0.397476)

然后我对两个循环做了同样的事情(一个每个一个map):

- bench = Benchmark.measure do
  %ul#client-list
    - @clients.each do |client|
      %li
        = link_to client.company, client

  = javascript_tag do
    = "var nearbys = [#{ @clients.map { |client| "['#{j client.name}', '#{j client.company}', '#{j client.email}']," }}]"

%p= bench.to_s

结果,大约80毫秒:

0.080000 0.000000 0.080000 ( 0.077940)

您可能想自己检查结果,但似乎 content_for 方法并不是解决此问题的非常有效的方法。

编辑:仅供引用,这是使用 ree 1.8.7 和 Rails 3.2.6 测试的

编辑2:

如何在不使用内联 JavaScript 的情况下重写此示例。我首先将所有必需的参数移至 data- 属性中,例如在 View 中:

<% @items.each do |item| %>
  <div class="item" data-name="<%= item.name %>"
                    data-lat="<%= item.lat %>"
                    data-long="<%= item.long %>">
    <%= item.name %>
  </div>
<% end %>

(您也可以从 div 内部获取名称,但将所有内容都放在数据属性中会更加一致。)

然后在 JavaScript 中,您可以按如下方式映射数据(假设 jquery):

var nearbys = $('.item').map(function() {
  return [ $(this).data("name"), $(this).data("lat"), $(this).data("long") ];
});

这样您就可以将所有 JavaScript 整齐地保存在一个单独的文件中,并在客户端收集数据。

关于ruby-on-rails - 一个 View 中有多个类似的循环,更好的做法吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/12123400/

相关文章:

sql - Rails SQL "select in"跨多个列 : where (code1, code2) in ( ("A", 1), ("A", 3), ("Q", 9))

html - AJAX 调用后显示数据,如何在 Controller 中呈现?

ruby-on-rails - Rails Assets 管道 : controller specific stylesheets

ruby-on-rails - 如何清理我的 Puma Logs?

mysql - Ruby on Rails 中错误的时区转换

ruby-on-rails - Rails - has_secure_password 密码和 PIN - password_digest 限制

ruby-on-rails - bundle 安装错误,意外 ':'

java - 我们可以从网站提交的表格中获取哪些可能的数据

javascript - 如果没有内容,如何隐藏 Bootstrap 警报?

ruby-on-rails - 是否可以在 Heroku 上使用修改 nginx 配置文件并使用 X-Accel-Redirect?