【问题标题】:Ruby/Rails - Add records to an object with each loop iteration / Object vs ArraysRuby/Rails - 在每次循环迭代/对象与数组时向对象添加记录
【发布时间】:2011-06-09 07:08:18
【问题描述】:

我试图弄清楚如何为循环的每次迭代添加记录到现有对象。我很难发现对象和数组之间的区别。

我有这个

 @events = Event.find(1)
 @loops = Choices.find(:all, :limit => 5)  #so loop for 5 instances of choice model
 for loop in @loops
       @events = Event.find(:all,:conditions => ["event.id = ?", loop.event_id ])
 end

我正在尝试根据循环变量的 id 向现有 @events 对象添加新事件。但是 ( = ) 运算符只是创建了 @events 对象的一个​​新实例。

我尝试将 ( += ) 和 (

“你没想到有一个 nil 对象!你可能期待一个 Array 的实例。在评估 nil 时发生错误”

我尝试创建一个数组

 events = []
 events << Event.find(1)
 @loops = Choices.find(:all, :limit => 5)  #so loop for 5 instances of choice model
 for loop in @loops
       events << Event.find(:all,:conditions => ["event.id = ?", loop.event_id ])
 end

但我不知道如何在视图中调用该数组属性

对于对象,我能够在视图中创建一个循环并调用该对象的所有属性...

<table> 
<% for event in @events %>
<tr>
  <td><%= link_to event.title, event %></td>
  <td><%= event.start_date %></td>
  <td><%= event.price %></td>
</tr>
<% end %>
</table>

如何使用数组集来做到这一点?

所以问题是

1) 数组和对象有什么区别?
2) 有没有办法为每次迭代添加到现有对象中?
3)如果我使用数组,有没有办法在视图中调用每个数组记录的属性?

【问题讨论】:

    标签: ruby-on-rails ruby arrays hash


    【解决方案1】:
    @events = []
    @events << Event.find(1)
    @loops = Choices.find(:all, :limit => 5)
    for loop in @loops
        es = Event.find(:all, :conditions => ["event.id = ?", loop.event_id])
        for e in es
            @events << e
        end
    end
    

    【讨论】:

    • 这个答案会产生六个查询,而这可以分两次完成。
    • 对。更多关于“N+1 查询问题”的信息:guides.rubyonrails.org/…
    • 没错。但是,它也是对 OP 代码的最短和最直接的翻译,并且应该清楚地说明 OP 代码需要进行的一些更改才能使该代码完全正常工作,即使不是尽可能快。
    • 它是否仍然适用于 rias 3.2.8 和 ruby​​ 1.9.3?因为我遇到了一个错误并且不确定它正在发生什么。 undefined method '&lt;&lt;' for #&lt;Post:0x007fb943fd0c60&gt;
    【解决方案2】:

    首先,退后一步。让我们弄清楚你到底想要做什么。

    对我来说,这似乎是:找到前五个选项引用的所有事件

    如果这就是您想要做的全部,请通过以下方式为自己节省一些时间和查询:

    @choices = Choices.limit(5).include(:event)

    这假设两者之间存在has_{one,many}/belongs_to 关联,我认为应该存在关联。虽然类名很模糊,我可能会遗漏一些东西。

    然后您可以遍历@choices 并拉出与之关联的event。或者使用类似Enumerable#collect

    您可以使用Array#push or Array#<<Event.find(1) 添加到此生成的数组中。

    【讨论】:

    • 这是一个很好的答案,但似乎他正在尝试添加 id = 1 的事件,无论选择中出现什么。
    【解决方案3】:
    1. 在 JavaScript 中,有一个 Object 存储键值对(类似于 Ruby 中的 Hash),还有一个 Array(存储一组有序的值)。在 JavaScript 中,数组(与所有对象一样)可以随时添加任意属性。这会导致 JavaScript 中的 Object 和 Array 之间出现一些混淆。在 Ruby 中,情况并非如此。

      • 在 Ruby 中,Object 是基类 from which all other objects inherit。您可以阅读 Object here 的文档。
      • 在 Ruby 中,Array 是一个用于存储有序值列表的类。您可以阅读 Array here 的文档。
      • 在 Ruby 中,只要有方法,几乎​​所有东西都是“对象”。
         

      不过,我认为您的意思可能不是“对象”,而是“实例变量”。实例变量以“at”符号为前缀,例如@foo。变量本身不是对象,也不包含对象;相反,它们指向(或引用)对象。它们引用的对象可能有许多不同的类型。

    2. @Justice 向您展示了一种在循环内将项目添加到数组的方法。

    3. 如果您有一个实例变量是一个数组,您可以在视图中迭代它的值。其语法取决于您使用的模板系统(Erb、Haml 等)

    【讨论】:

      【解决方案4】:

      我们必须猜测,因为没有关于模型及其关系的详细信息。但是假设 choice has_many events 我会这样做(如果您关心效率,请添加事件的包含):

      @events = [Event.find(1)] + Choice.all(:limit => 5).map(&:events).flatten
      

      即使您没有 Rails 关联,这也应该可以工作,尽管它看起来更丑陋(ActiveRecord 在接受什么作为参数方面是不是有点混杂?):

      @events = Event.find(1, Choice.all(:limit => 5).map(&:event_id))
      

      【讨论】:

        【解决方案5】:

        如果您使用的是 Rails 3,您可以这样做:

        loops = [1] + Choice.select("event_id").limit(5).collect {|x| x.event_id}
        @events = Event.all(:conditions => ["id in (?)", loops])
        

        这会将来自选项的所有 event_id 收集到一个数组中,附加到事件 id 1,然后可以在 Event.all 查询的 IN 子句中使用。这应该比遍历您的选择并为每个选择生成查询更有效。

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2017-10-25
          • 1970-01-01
          • 2019-10-02
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多