使用“has_many_through”关联创建记录 – Ruby on Rails

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

Create Record With "has_many_through" Association – Ruby on Rails

问题

我有一个has_many_through关联,其中User通过ProjectUser拥有许多Project。Rails具有一些魔法,可以使用以下方式更新此关系:

  1. u = User.first
  2. u.update(project_ids: [...])

是否有一种干净的方法可以使用create来做同样的事情?

运行User.create(name: ..., project_ids: [...])会失败,错误信息为Validation failed: Project users is invalid

我怀疑这是因为Rails在创建User记录之前尝试创建ProjectUser记录,并在连接表上进行了一些内置验证,以验证连接的两侧是否已经存在。ProjectUser模型没有自定义验证。

  1. class ProjectUser < ApplicationRecord
  2. belongs_to :project
  3. belongs_to :user
  4. end

是否有一种简单的方法来解决这个问题?

英文:

I have a has_many_through association where Users have many Projects through ProjectUsers. Rails has some magic that allows updating this relationship with:

  1. u = User.first
  2. u.update(project_ids: [...])

Is there a clean way to do the same thing with create?

Running User.create(name: ..., project_ids: [...]) fails with Validation failed: Project users is invalid.

I suspect this is because Rails tries to create the ProjectUser record before creating the User record and has some built-in validation on join tables to validate that both sides of the join already exist. The ProjectUser model has no custom validation.

  1. class ProjectUser &lt; ApplicationRecord
  2. belongs_to :project
  3. belongs_to :user
  4. end

Is there a simple way to get around this?

答案1

得分: 3

Active Record 支持大多数具有标准名称的关联的自动识别。然而,Active Record 不会自动识别包含 :through 或 :foreign_key 选项的双向关联。(您可以在这里查看)

因此,您必须明确定义 inverse_of

  1. class Project &lt; ApplicationRecord
  2. has_many :project_users, foreign_key: :project_id, inverse_of: :project
  3. has_many :users, through: :project_users
  4. end
  5. class User &lt; ApplicationRecord
  6. has_many :project_users, foreign_key: :user_id, inverse_of: :user
  7. has_many :projects, through: :project_users
  8. end
  9. class ProjectUser &lt; ApplicationRecord
  10. belongs_to :project
  11. belongs_to :user
  12. end
英文:

Active Record supports automatic identification for most associations with standard names. However, Active Record will not automatically identify bi-directional associations that contain the :through or :foreign_key options. (You can check here)

So you have to define inverse_of explicitly.

  1. class Project &lt; ApplicationRecord
  2. has_many :project_users, foreign_key: :project_id, inverse_of: :project
  3. has_many :users, through: :project_users
  4. end
  5. class User &lt; ApplicationRecord
  6. has_many :project_users, foreign_key: :user_id, inverse_of: :user
  7. has_many :projects, through: :project_users
  8. end
  9. class ProjectUser &lt; ApplicationRecord
  10. belongs_to :project
  11. belongs_to :user
  12. end

答案2

得分: 0

通常人们使用hmt(而不是has_and_belongs_to_many)是因为他们有其他字段需要在关联表中填充,因此人们通常使用关联表创建模型记录的三元组,例如。

  1. ProjectUser.create! the_extra_field: "Foo", user: User.create!(name: "Jim"), project: Project.create!(title: "Project X")

显然,如果您已经有现有的UserProject,那么您会使用它们而不是创建新的。

英文:

Generally people use hmt (instead of has_and_belongs_to_many) because they have other fields that they're interested in populating in the join table, hence people usually create the triplet of model records using the join table, eg.

  1. ProjectUser.create! the_extra_field: &quot;Foo&quot;, user: User.create!(name: &quot;Jim&quot;), project: Project.create!(title: &quot;Project X&quot;)

Obviously if you already have an existing User or Project then you'd use those instead of creating new ones.

答案3

得分: -2

我相信你需要使用 accepts_nested_attributes_for

  1. class User &lt; ApplicationRecord
  2. has_many :project_users
  3. has_many :projects, through: :project_users
  4. accepts_nested_attributes_for :projects
  5. end

这应该能帮助你创建带有关联项目的用户,就像你期望的那样

  1. User.create(name: 'John', project_ids: [...])
英文:

I believe that you need to use accepts_nested_attributes_for

  1. class User &lt; ApplicationRecord
  2. has_many :project_users
  3. has_many :projects, through: :project_users
  4. accepts_nested_attributes_for :projects
  5. end

That must help you to create users with associated projects like you expected

  1. User.create(name: &#39;John&#39;, project_ids: [...])

huangapple
  • 本文由 发表于 2023年6月1日 23:34:41
  • 转载请务必保留本文链接:https://go.coder-hub.com/76383552.html
匿名

发表评论

匿名网友

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

确定