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

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

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

问题

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

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

账户模型

module AccountBlock
  class Account < AccountBlock::ApplicationRecord
    ActiveSupport.run_load_hooks(:account, self)
    self.table_name = :accounts

    include Wisper::Publisher

    has_many :user_categories, class_name: "BxBlockCategories::UserCategory", dependent: :destroy
    has_many :categories, class_name: "BxBlockCategories::Category", through: "user_categories", dependent: :delete_all
  end
end

用户类别模型

module BxBlockCategories
  class UserCategory < ApplicationRecord
    self.table_name = :user_categories

    belongs_to :account, class_name: "AccountBlock::Account", foreign_key: :account_id
    belongs_to :category, class_name: "BxBlockCategories::Category", foreign_key: :category_id
  end
end

类别模型

module BxBlockCategories
  class Category < BxBlockCategories::ApplicationRecord
    self.table_name = :categories

    has_and_belongs_to_many :sub_categories, join_table: :categories_sub_categories, dependent: :destroy
    has_many :contents, class_name: "BxBlockContentmanagement::Content", dependent: :destroy
    has_many :ctas, class_name: "BxBlockCategories::Cta", dependent: :nullify
    has_many :user_categories, class_name: "BxBlockCategories::UserCategory", dependent: :destroy
    has_many :accounts, class_name: "AccountBlock::Account", through: :user_categories
  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

module AccountBlock
  class Account &lt; AccountBlock::ApplicationRecord
    ActiveSupport.run_load_hooks(:account, self)
    self.table_name = :accounts

    include Wisper::Publisher

    has_many :user_categories, class_name: &quot;BxBlockCategories::UserCategory&quot;, dependent: :destroy
    has_many :categories, class_name: &quot;BxBlockCategories::Category&quot;, through: &quot;user_categories&quot;, dependent: :delete_all

end

User Category Model

module BxBlockCategories
  class UserCategory &lt; ApplicationRecord
    self.table_name = :user_categories

    belongs_to :account, class_name: &quot;AccountBlock::Account&quot;, foreign_key: :account_id
    belongs_to :category, class_name: &quot;BxBlockCategories::Category&quot;, foreign_key: :category_id
  end
end

Category Model

module BxBlockCategories
  class Category &lt; BxBlockCategories::ApplicationRecord
    self.table_name = :categories


    has_and_belongs_to_many :sub_categories,
                            join_table: :categories_sub_categories, dependent: :destroy

    has_many :contents, class_name: &quot;BxBlockContentmanagement::Content&quot;, dependent: :destroy
    has_many :ctas, class_name: &quot;BxBlockCategories::Cta&quot;, dependent: :nullify

    has_many :user_categories, class_name: &quot;BxBlockCategories::UserCategory&quot;, dependent: :destroy
    has_many :accounts, class_name: &quot;AccountBlock::Account&quot;, through: :user_categories
             
  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

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

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

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

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

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

module AccountBlock
  # ApplicationRecord被解析为AccountBlock::ApplicationRecord
  class Account < ApplicationRecord
    ActiveSupport.run_load_hooks(:account, self)
    self.table_name = :accounts
    has_many :user_categories,
      # 好 - 我们在另一个模块中引用一个常量。
      class_name: "BxBlockCategories::UserCategory",
      dependent: :destroy
    has_many :categories,
      class_name: "BxBlockCategories::Category",
      through: "user_categories",
      dependent: :delete_all
  end
end
module BxBlockCategories
  class UserCategory < ApplicationRecord
    self.table_name = :user_categories
    # 当可以从关联的名称推导出时,您不需要指定`foreign_key`。
    belongs_to :account, class_name: 'AccountBlock::Account'
    belongs_to :category
  end
end
module BxBlockCategories
  class Category < ApplicationRecord
    self.table_name = :categories
    has_many :user_categories, dependent: :destroy
    has_many :accounts,
      through: :user_categories,
      class_name: 'AccountBlock::Account'
  end
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:

AccountBlock::Account.first.categories.each do |category|
  puts category.name
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:

module AccountBlock
  # ApplicationRecord is resolved as AccountBlock::ApplicationRecord 
  class Account &lt; ApplicationRecord 
    ActiveSupport.run_load_hooks(:account, self)
    self.table_name = :accounts
    has_many :user_categories, 
      # good - we are referring to a constant in another module.
      class_name: &quot;BxBlockCategories::UserCategory&quot;, 
      dependent: :destroy
    has_many :categories, 
      class_name: &quot;BxBlockCategories::Category&quot;, 
      through: &quot;user_categories&quot;, 
      dependent: :delete_all
 end
end
module BxBlockCategories
  class UserCategory &lt; ApplicationRecord
    self.table_name = :user_categories
    # you don&#39;t need specify `foreign_key` when it can be derived from the name of the association. 
    belongs_to :account, class_name: &#39;AccountBlock::Account&#39;
    belongs_to :category
  end
end
module BxBlockCategories
  class Category &lt; ApplicationRecord
    self.table_name = :categories
    has_many :user_categories, dependent: :destroy
    has_many :accounts, 
      through: :user_categories,
      class_name: &#39;AccountBlock::Account&#39;
  end
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:

确定