在Rails 6中的”has_many through”关联中,我做错了什么?

huangapple go评论90阅读模式
英文:

What Am I doing wrong in the has many through association In Rails 6?

问题

所以,我有3个模型(accountuser_categorycategory),每个模型都在不同的文件夹内。

我定义了一个has_many through关联,通过中间表User CategoryAccount关联到Category,这样用户可以拥有多个类别,但它没有按预期工作。

账户模型

  1. module AccountBlock
  2. class Account < AccountBlock::ApplicationRecord
  3. ActiveSupport.run_load_hooks(:account, self)
  4. self.table_name = :accounts
  5. include Wisper::Publisher
  6. has_many :user_categories, class_name: "BxBlockCategories::UserCategory", dependent: :destroy
  7. has_many :categories, class_name: "BxBlockCategories::Category", through: "user_categories", dependent: :delete_all
  8. end
  9. end

用户类别模型

  1. module BxBlockCategories
  2. class UserCategory < ApplicationRecord
  3. self.table_name = :user_categories
  4. belongs_to :account, class_name: "AccountBlock::Account", foreign_key: :account_id
  5. belongs_to :category, class_name: "BxBlockCategories::Category", foreign_key: :category_id
  6. end
  7. end

类别模型

  1. module BxBlockCategories
  2. class Category < BxBlockCategories::ApplicationRecord
  3. self.table_name = :categories
  4. has_and_belongs_to_many :sub_categories, join_table: :categories_sub_categories, dependent: :destroy
  5. has_many :contents, class_name: "BxBlockContentmanagement::Content", dependent: :destroy
  6. has_many :ctas, class_name: "BxBlockCategories::Cta", dependent: :nullify
  7. has_many :user_categories, class_name: "BxBlockCategories::UserCategory", dependent: :destroy
  8. has_many :accounts, class_name: "AccountBlock::Account", through: :user_categories
  9. end

在Rails 6中的”has_many through”关联中,我做错了什么?

如果我使用category.account,它可以工作,但对于account.categories,它返回一个空的关联。为什么会这样呢?

希望有人能帮我解决这个问题。

英文:

So, I have 3 models(account, user_category, category) every model is inside different folders.
I've defined a has_many through association to associate Account to Category through middle table User Category so that a user can have many categories but it is not working as intended.

Account Model

  1. module AccountBlock
  2. class Account &lt; AccountBlock::ApplicationRecord
  3. ActiveSupport.run_load_hooks(:account, self)
  4. self.table_name = :accounts
  5. include Wisper::Publisher
  6. has_many :user_categories, class_name: &quot;BxBlockCategories::UserCategory&quot;, dependent: :destroy
  7. has_many :categories, class_name: &quot;BxBlockCategories::Category&quot;, through: &quot;user_categories&quot;, dependent: :delete_all
  8. end

User Category Model

  1. module BxBlockCategories
  2. class UserCategory &lt; ApplicationRecord
  3. self.table_name = :user_categories
  4. belongs_to :account, class_name: &quot;AccountBlock::Account&quot;, foreign_key: :account_id
  5. belongs_to :category, class_name: &quot;BxBlockCategories::Category&quot;, foreign_key: :category_id
  6. end
  7. end

Category Model

  1. module BxBlockCategories
  2. class Category &lt; BxBlockCategories::ApplicationRecord
  3. self.table_name = :categories
  4. has_and_belongs_to_many :sub_categories,
  5. join_table: :categories_sub_categories, dependent: :destroy
  6. has_many :contents, class_name: &quot;BxBlockContentmanagement::Content&quot;, dependent: :destroy
  7. has_many :ctas, class_name: &quot;BxBlockCategories::Cta&quot;, dependent: :nullify
  8. has_many :user_categories, class_name: &quot;BxBlockCategories::UserCategory&quot;, dependent: :destroy
  9. has_many :accounts, class_name: &quot;AccountBlock::Account&quot;, through: :user_categories
  10. end

在Rails 6中的”has_many through”关联中,我做错了什么?

It works if I do category.account but returns an empty Association for account.categories.

Why is that?

I would love someone can help me.

I've included I've tried so far in the code above.

答案1

得分: 1

这里的问题不在于关联。问题在于您正在犯一个典型的初学者错误,尝试在整个记录集合上调用一个实例方法。

想象一下,你面前有一群人,然后你问:“你叫什么名字?” - 这会怎么工作?他们都会同时喊出他们的名字吗,还是只是盯着你看,好像你是个傻瓜?

如果您想要获取给定账户的类别,您需要遍历结果:

  1. AccountBlock::Account.first.categories.each do |category|
  2. puts category.name
  3. end

关联关系也过于复杂,您可以通过正确使用模块嵌套来消除许多过度配置:

  1. module AccountBlock
  2. # ApplicationRecord被解析为AccountBlock::ApplicationRecord
  3. class Account < ApplicationRecord
  4. ActiveSupport.run_load_hooks(:account, self)
  5. self.table_name = :accounts
  6. has_many :user_categories,
  7. # 好 - 我们在另一个模块中引用一个常量。
  8. class_name: "BxBlockCategories::UserCategory",
  9. dependent: :destroy
  10. has_many :categories,
  11. class_name: "BxBlockCategories::Category",
  12. through: "user_categories",
  13. dependent: :delete_all
  14. end
  15. end
  1. module BxBlockCategories
  2. class UserCategory < ApplicationRecord
  3. self.table_name = :user_categories
  4. # 当可以从关联的名称推导出时,您不需要指定`foreign_key`。
  5. belongs_to :account, class_name: 'AccountBlock::Account'
  6. belongs_to :category
  7. end
  8. end
  1. module BxBlockCategories
  2. class Category < ApplicationRecord
  3. self.table_name = :categories
  4. has_many :user_categories, dependent: :destroy
  5. has_many :accounts,
  6. through: :user_categories,
  7. class_name: 'AccountBlock::Account'
  8. end
  9. end
英文:

The problem here isn't the assocations. It's that you're making a classic beginner misstake and calling an instance method on an whole collection of records.

Imagine you have an entire group of people in front of you and you ask "What is your name?" - how would that work? Are they all going to shout their names at the same time or just stare at your like you're an idiot?

If you want to get the categories for a given account you need to loop through the results:

  1. AccountBlock::Account.first.categories.each do |category|
  2. puts category.name
  3. end

The assocations are also very overcomplicated and you can get rid of a lot of over-configuration by just using the module nesting correctly:

  1. module AccountBlock
  2. # ApplicationRecord is resolved as AccountBlock::ApplicationRecord
  3. class Account &lt; ApplicationRecord
  4. ActiveSupport.run_load_hooks(:account, self)
  5. self.table_name = :accounts
  6. has_many :user_categories,
  7. # good - we are referring to a constant in another module.
  8. class_name: &quot;BxBlockCategories::UserCategory&quot;,
  9. dependent: :destroy
  10. has_many :categories,
  11. class_name: &quot;BxBlockCategories::Category&quot;,
  12. through: &quot;user_categories&quot;,
  13. dependent: :delete_all
  14. end
  15. end
  1. module BxBlockCategories
  2. class UserCategory &lt; ApplicationRecord
  3. self.table_name = :user_categories
  4. # you don&#39;t need specify `foreign_key` when it can be derived from the name of the association.
  5. belongs_to :account, class_name: &#39;AccountBlock::Account&#39;
  6. belongs_to :category
  7. end
  8. end
  1. module BxBlockCategories
  2. class Category &lt; ApplicationRecord
  3. self.table_name = :categories
  4. has_many :user_categories, dependent: :destroy
  5. has_many :accounts,
  6. through: :user_categories,
  7. class_name: &#39;AccountBlock::Account&#39;
  8. end
  9. end

答案2

得分: 0

我发现了我之前做错的地方。

在账户模型文件中,当我使用through: &quot;user_categories&quot;时,我使用了一个字符串字面量,这导致了问题。相反,我必须使用一个符号,像这样 through: :user_categories

英文:

So, I figured out what I was doing wrong.

In the Account Model file when I used through: &quot;user_categories&quot; I used a string literal which was causing the issue. Instead I had to use a symbol like this through: :user_categories.

huangapple
  • 本文由 发表于 2023年3月3日 18:58:52
  • 转载请务必保留本文链接:https://go.coder-hub.com/75626203.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定