【问题标题】:select single association from has_many through in Rails在 Rails 中从 has_many 中选择单个关联
【发布时间】:2012-06-26 23:11:54
【问题描述】:

在使用 has_many through 关联时,是否有任何(干净的)方法可以访问单个关联?

例如,要获取食谱的所有成分,我可以这样写:

@ingredients = @recipe.ingredients

但是,如果我已经选择了一种成分,并且我想将数据添加到配方/成分的连接表中,我无法找到添加数据的简洁方法。

我无法使用

访问单一成分关联的数量
ingredient = Ingredient.find(an_id)  

amount = @recipe.ingredient.amount

连接表中存储的单一成分信息的选择方法是什么?

【问题讨论】:

  • 所以你找到了你想要的食谱,你已经找到了那个食谱的成分。您想编辑其中一种成分的属性,还是想为之前选择的食谱添加新成分?或者是否有另一个关于您要填充的成分的联接表?
  • 有一个关于食谱和成分的连接表,其中包含有关与它们相关的食谱特定的成分的信息,即每种成分的量。

标签: sql ruby-on-rails ruby-on-rails-3 associations has-many-through


【解决方案1】:

选项:select 在这种情况下非常有用。例如

class Recipe
  has_many :ingredients, through: ingredients_recipes, select: "ingredinets.*, ingredients_recipes.some_additional_column as some_additional_column"
  ....

然后打电话

Recipe.first.ingredients.first.some_additional_column # => profit!

你也可以在你的作用域中使用它。

【讨论】:

    【解决方案2】:

    连接表对您很重要,因此它应该有一个名称。 你可以称它为recipe_ingredient,但一个真实的名字有助于在精神上不混淆事物。 (它帮助我们讨论这个问题)

    假设连接表被调用,例如slot

    class Recipe
      has_many :slots
      has_many :ingredients, :through => :slots
      ..
    class Slot
      belongs_to :recipe
      belongs_to :ingredient
      ...
    

    你通过调用得到一个定义的槽

    @slot = @recipe.slots.where(:ingredients_id => @ingredient).first 
    @slot.amount = 20
    

    为了提高效率并确保每个组合只存在一次,您可以为插槽定义一个唯一的复合索引以跨越 recipe_id 和成分 ID

    【讨论】:

      【解决方案3】:

      你可以@ingredient = @recipe.ingredients.first(如果它真的是唯一的,不知道你怎么能确定这一点。)

      假设您已经选择了成分,就像在变量中一样,您可以像设置任何其他 ActiveRecord 对象一样设置它们。

      @ingredient = @recipe.ingredients.first
      @ingredient.amount = 15 #or @ingredient.amount = params[:amount] (if you get the new value from POST)
      @ingredient.unit = "Ounces"
      @ingredient.save
      

      如果您只是想检索配方中每种成分的属性并对其进行处理,例如在视图中的一些 html 标记中显示它们,您可以试试这个。

      @ingredients = @recipe.ingredients
         @ingredients.each do |ingr|
          info = %w[amount, brand, id, recipe_id , unit].map do |attr|
            ingr.send(attr)
          end
      

      在每个内部循环的末尾,数组“信息”将是一种成分的所有属性。(假设您将它们包含在信息数组中)

      这是一个可以用来存储关联的表格示例,它应该与 rails :through => :recipe_ingedient 方法一起使用:

      CREATE TABLE `recipe_ingredient` (
        `id` int(11) NOT NULL AUTO_INCREMENT,
        `recipe_id` int(11) NOT NULL,
        `ingedient_id` int(11) NOT NULL,
        `created_at` datetime DEFAULT NULL,
        `updated_at` datetime DEFAULT NULL,
        PRIMARY KEY (`id`)
      ) ENGINE=InnoDB AUTO_INCREMENT=59 DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci$$
      

      【讨论】:

      • 你想如何访问@recipe.ingeredient?这将引发 NameError "undefined method `ingredient' for #"
      • 我了解一次选择一种成分背后的逻辑,但我想知道在食谱和成分之间的连接表中存储数据的最有效方法是什么。
      【解决方案4】:

      我不明白这样的事情怎么可能存在。如果您有 许多 个关联对象,则需要指定 哪个 您想要。这与其说是 Rails 的限制,不如说是……我不知道,集合论?逻辑? 您可以使用.first (ingredient = @recipe.ingredients.first) 获取关联对象之一,但除非您还指定订单,否则无法确定它将是哪一个。

      【讨论】:

      • 这很有趣……集合论。它完全在数据库和一个或两个表的 has_many 关系的限制内只有一个记录(在表本身或只有一个具有匹配键的记录)。所以很明显,这不是任何事情的限制。不信就去试试吧。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2023-03-22
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多