Rails 4 访问连接表属性 [英] Rails 4 Accessing Join Table Attributes

查看:38
本文介绍了Rails 4 访问连接表属性的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个用于食谱应用程序的 has_many through 连接表设置,其中 IngredientMeal 通过 MealIngredient 连接.在MealIngredient 中,我有meal_idingredient_idamount.我的问题是:如何访问 amount 列?

I have a has_many through join table setup for a recipe app where Ingredient and Meal connect through MealIngredient. Within MealIngredient, I have meal_id, ingredient_id, and amount. My question is: How can I access the amount column?

在我的食谱视图中,我循环查看成分:

In my recipe view, I loop through the ingredients:

@meal.ingredients.each do |i|

我可以访问成分的属性,但不能访问 MealIngredient 加入记录中的数量.

I can access the properties of the ingredient but not the amount from the MealIngredient join record.

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

I tried using includes in the query doing @meal.ingredients.includes(:meal_ingredients), but I'm unsure of how to access the amount within the aforementioned loop. When I use i.inspect, I don't see any references to the meal_ingredients table at all.

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

Is there some way to access the variable within that loop using i.amount?

在此先感谢您的帮助!

推荐答案

更新于 08/01/2020 - RPECK

为此苦苦挣扎了几个月,直到我们找到了合适的解决方案:

Struggled with this for months until we found an appropriate solution:

--

ActiveRecord 关联扩展

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

The problem you have is that Rails will just use the foreign_keys in your join table to load the associative data you need. Unless you actually load the join model directly, it won't give you the ability to access the join attributes

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

Some foraging lead us to ActiveRecord Association Extensions - a way to access the intermediary data in between different ActiveRecord Associations (using a collection called proxy_association). This will allow you to access the extra attributes from the join model, appending them to your "original" model:

#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, { -> extending: IngredientAmount }, through: :meal_ingredients
end

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

    # => Load
    # => Triggered whenever module is invoked (allows us to populate response data)
    # => #<Method: ActiveRecord::Relation#load(&block) c:/Dev/Apps/pwinty-integration/.bundle/ruby/2.7.0/gems/activerecord-6.0.2.1/lib/active_record/relation.rb:614>
    def load(&block)

       # => This is called from the following reference - if you want to dig deeper, you can use method(:exec_queries).source_location
       # => c:/Dev/Apps/pwinty-integration/.bundle/ruby/2.7.0/gems/activerecord-6.0.2.1/lib/active_record/association_relation.rb:42
      unless loaded?
        exec_queries do |record|
          record.assign_attributes({amount: items[record.id]}) if items[record.id].present?
        end
      end

    end

    # Load
    # Deprecated with AR 6.0
    #def load
    #   amounts.each do |amount|
    #       proxy_association.target << amount
    #   end
    #end

    #Private
    private

    #Amounts
    # Not needed after AR 6.0
    #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)
        through_collection.pluck(through_source_key, :amount).map{ |id, amount| { id => amount } }.inject(:merge) #-> { id: record, id: record }
    end

    #Target
    # This no longer works with AR 6.0+
    #def target_collection
    #   #load_target
    #   proxy_association.target
    #end

end

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

This should append the amount attribute to your ingredient objects now, allowing you to perform:

@meal = Meal.find 1
@meal.ingredients.each do |ingredient|
   ingredient.amount
end

这篇关于Rails 4 访问连接表属性的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆