Rails 4访问连接表属性
我有一个用于配方应用程序的has_many through
连接表设置,其中Ingredient
和Meal
通过MealIngredient
连接。 在MealIngredient
,我有meal_id
, ingredient_id
和amount
。 我的问题是:如何访问amount
列?
在我的食谱视图中,我遍历了各种成分:
@meal.ingredients.each do |i|
我可以访问成分的属性,但不能访问MealIngredient
记录中的金额。
我尝试在查询中使用includes
@meal.ingredients.includes(:meal_ingredients)
,但我不确定如何访问上述循环中的amount
。 当我使用i.inspect
,我根本没有看到对meal_ingredients
表的任何引用。
有没有办法使用i.amount
访问该循环中的变量?
预先感谢您的任何帮助!
啊,好老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
这应该现在将amount
属性附加到您的ingredient
对象,允许您执行:
@meal = Meal.find 1 @meal.ingredients.each do |ingredient| ingredient.amount end
在这种情况下,您应该遍历meal_ingredients
协会。 您应该急于加载ingredients
关联以减少数据库查询。
@meal.meal_ingredients.includes(:ingredient).each do |meal_ingredient| puts meal_ingredient.amount puts meal_ingredient.ingredient.name end
UPDATE
这次更新是在Rich Peck回答之后发生的,但我认为有一种更简单的方法可以实现他所做的。
@meal.ingredients.select('ingredients.*, meal_ingredients.amount').each do |ingredient| puts ingredient.amount puts ingredient.name end