Rails 4访问连接表属性

Jus*_*tin 25 sql ruby-on-rails ruby-on-rails-4

我有一个has_many through连接表设置为配方应用程序在哪里IngredientMeal连接MealIngredient.在MealIngredient,我有meal_id,ingredient_idamount.我的问题是:我如何访问该amount列?

在我的食谱视图中,我遍历了各种成分:

@meal.ingredients.each do |i|
Run Code Online (Sandbox Code Playgroud)

我可以访问成分的属性,但不能访问MealIngredient连接记录中的金额.

我尝试includes在查询中使用@meal.ingredients.includes(:meal_ingredients),但我不确定如何访问amount前面提到的循环.当我使用时i.inspect,我根本看不到任何对该meal_ingredients表的引用.

是否有某种方法可以使用该循环访问变量i.amount

预先感谢您的任何帮助!

jvn*_*ill 27

在这种情况下,您应该遍历meal_ingredients关联.您应该急切加载ingredients关联以减少数据库查询.

@meal.meal_ingredients.includes(:ingredient).each do |meal_ingredient|
  puts meal_ingredient.amount
  puts meal_ingredient.ingredient.name
end
Run Code Online (Sandbox Code Playgroud)

UPDATE

这次更新是在Rich Peck回答之后发生的,但我认为有一种更简单的方法可以实现他的目标.

@meal.ingredients.select('ingredients.*, meal_ingredients.amount').each do |ingredient|
  puts ingredient.amount
  puts ingredient.name
end
Run Code Online (Sandbox Code Playgroud)


Ric*_*eck 27

啊,这个古老的how do I access my extra join table attributes问题.我们为MONTHS苦苦挣扎,直到我们提出解决方案

-

ActiveRecord Association Extensions

你遇到的问题是Rails只会使用foreign_keys你的连接表来加载你需要的关联数据.除非您实际直接加载连接模型,否则它将无法访问连接属性

一些觅食引导我们ActiveRecord Association Extensions- 一种在不同的ActiveRecord关联之间访问中间数据的方法(使用一个名为的集合proxy_association).这将允许您从连接模型访问额外属性,将它们附加到"原始"模型:

#app/models/ingredient.rb
class Ingredient < ActiveRecord::Base
   attr_accessor :amount #-> need a setter/getter
end

#app/models/meal.rb
class Meal < ActiveRecord::Base
   has_many :meal_ingredients
   has_many :ingredients, through: :meal_ingredients, extend: IngredientAmount
end

#app/models/concerns/ingerdient_amount.rb
module IngredientAmount

    #Load
    def load
        amounts.each do |amount|
            proxy_association.target << amount
        end
    end

    #Private
    private

    #Amounts
    def amounts
        return_array = []
        through_collection.each_with_index do |through,i|
            associate = through.send(reflection_name)
            associate.assign_attributes({amount: items[i]}) if items[i].present?
            return_array.concat Array.new(1).fill( associate )
        end
        return_array
    end

    #######################
    #      Variables      #
    #######################

    #Association
    def reflection_name
        proxy_association.source_reflection.name
    end

    #Foreign Key
    def through_source_key
        proxy_association.reflection.source_reflection.foreign_key
    end

    #Primary Key
    def through_primary_key
        proxy_association.reflection.through_reflection.active_record_primary_key
    end

    #Through Name
    def through_name
        proxy_association.reflection.through_reflection.name
    end

    #Through
    def through_collection
        proxy_association.owner.send through_name
    end

    #Captions
    def items
        through_collection.map(&:amount)
    end

    #Target
    def target_collection
        #load_target
        proxy_association.target
    end

end
Run Code Online (Sandbox Code Playgroud)

这应该立即将amount属性附加到您的ingredient对象,允许您执行:

@meal = Meal.find 1
@meal.ingredients.each do |ingredient|
   ingredient.amount
end
Run Code Online (Sandbox Code Playgroud)

  • 如何更新此示例中的"金额"?这工作正常,但我还需要更新值. (5认同)
  • 看起来我想要实现的解决方案.非常干净 - 不幸的是,无论如何我都会获得零值.使用byebug - 它甚至不加载属性(调用load).我想念什么吗?注意我在Rails 5 @RichardPeck上 (4认同)