【问题标题】:Identifying Model Instance by Two Relations通过两个关系识别模型实例
【发布时间】:2012-09-24 21:05:57
【问题描述】:

我试图通过它与它所属的其他两个模型(“Cut”和“Animal”)的关系来挑选一个模型(“Package”)的实例。虽然有许多带有 :cut_id 3 的包和许多带有 :animal_id 4 的包,但应该只有一个带有这两者,我想挑选一个并在表格中显示它的内容。

我尝试了以下 DIY 混乱,但它并没有真正起作用。 (cutfind 是我创建的一种方法,我知道它可以调用与给定动物相关的所有切割。)

<% @animal.cutfind.each do |cut| %>
  <tr>
    <td><%= cut.name %></td>
    <td><%= number_to_currency(cut.price) %></td>
    <td><%= cut.package_weight %> lb</td>
        <% @a = Package.where(:animal_id => @animal.id) %>
        <% @pset = @a.where(:cut_id => cut.id) %>
    <% @pset.each do |p| %>
        <td><%= p.original %></td>
        <td><%= p.left %></td>
    <% end %>
  </tr>
<%end%>

知道如何[更好地]做到这一点吗?谢谢。

更新:我尝试了这个其他 DIY 混乱并且遇到了同样的问题(甚至没有创建单元格,这让我相信 @pset 是空的)。

这是在我的动物模型中:

def packagefind
    Package.where(:animal_id => self.id)
end

然后我像这样更改了上面的内容:

<td><%= cut.package_weight %> lb</td>
        <% @pset = @animal.packagefind.where(:cut_id => cut.id) %>
    <% @pset.each do |p| %>
        <td><%= p.original %></td>
        <td><%= p.left %></td>
    <% end %>

【问题讨论】:

  • 您的 HTML 布局存在潜在问题。表的每一行 (tr) 应该具有相同数量的数据单元 (td),但不能保证 @pset 在每行中具有相同数量的元素,对吧?因此单元格的数量可能会有所不同。
  • Pset 实际上每次都是一样的。 each 块只是我处理我得到 (1) 个元素列表而不是单个元素的事实的 hacky 方式。我之前在使用blank.where(etc) 时遇到过这个问题,因为它总是返回一个列表,即使它被保证(如这里)是单个元素。
  • 这是为下面的,因为它不会让我在那里添加 cmets (!?)。所以它并不完全奏效。我现在收到一条错误消息,指出@p(我分配给 Package.find_by_cut_id_and_animal_id(cut.id, @animal.id) 属于 NilClass,这有点奇怪。这可能与架构差异有关吗?跨度>

标签: ruby-on-rails ruby-on-rails-3 activerecord associations models


【解决方案1】:

如果你定义了以下关系,Rails 会自动生成方法来帮助你找到关联的记录:

class Animal
  has_many :cuts
  has_many :packages, :through => :cuts
end

class Cut
  belongs_to :animal
  belongs_to :package
end

class Package
  has_many :cuts
  has_many :animals, :through => :cuts
end

在您的控制器中,以下行将 eager load 您的视图中需要的所有记录:

@animal = Animal.includes(:cuts => :package)

然后您的视图可以缩短为:

<% @animal.cuts.each do |cut| %>
  <tr>
    <td><%= cut.name %></td>
    <td><%= number_to_currency(cut.price) %></td>
    <td><%= cut.package_weight %> lb</td>
    <td><%= cut.package.original %></td>
    <td><%= cut.package.left %></td>
  </tr>
<%end%>

【讨论】:

    【解决方案2】:

    由于我无法对您的帖子发表评论,因此我猜测一下: 您有以下架构:

    剪切 -> 包装

    这里,“->”和“

    class Package < ActiveRecord::Base
      has_many :cuts
      has_many :animals
    end
    

    所以,你想要“the”包,它有 id 为 3 和 Animal id 为 4 的 Cut。 你试过了吗:

    x = Product.select { |product| product.cuts.include?(Cut.find(3)) }.select{ |product| product.animals.include?(Animal.find(4)) }
    

    ?

    编辑:我首先建议你使用

    Product.find_by_product_id_and_animal_id() 
    

    这没有用,但向 OP 展示了如何做到这一点

    【讨论】:

    • 其实有点不一样。动物有很多包裹。包裹属于一种动物。剪辑没有或不属于任何东西;它们只是手动关联的。 (包有一个 cut_id,但反之亦然)。我没试过。我不知道那存在。让我试一试。谢谢!
    • 抱歉,我编辑了它,因为我试过了,但它没有用(那个 find_by 的东西。试试新的。虽然它非常混乱和数据库密集型 :(
    • 我实际上让 find_by_etc 工作了。即使在我的 DIY 中也让我失望的主要问题是,在我创建动物之前,我一直在为包分配一个 animal_id,所以它总是为零。在创建动物之后,我不得不移动 package_create 方法,现在一切正常。感谢您的帮助!
    • 嗯,好的。所以实际上当前的答案对你没有帮助。我是 Stackoverflow 的新手。是否有“标准方法”来更改我的答案,以便未来的读者理解?
    • 没有。您的回答很好,而且我对 Stack Overflow 也很陌生。我没有使用它的唯一原因是 a) 模型之间的关系不是你建议的那样,b) find_by_cut_id_and_animal_id 的东西很好用,看起来更整洁。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-10-21
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多