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

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

Create Record With "has_many_through" Association – Ruby on Rails

问题

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

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

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

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

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

class ProjectUser < ApplicationRecord
  belongs_to :project
  belongs_to :user
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:

u = User.first
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.

class ProjectUser &lt; ApplicationRecord
  belongs_to :project
  belongs_to :user
end

Is there a simple way to get around this?

答案1

得分: 3

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

因此,您必须明确定义 inverse_of

class Project &lt; ApplicationRecord
  has_many :project_users, foreign_key: :project_id, inverse_of: :project
  has_many :users, through: :project_users
end

class User &lt; ApplicationRecord
  has_many :project_users, foreign_key: :user_id, inverse_of: :user
  has_many :projects, through: :project_users
end

class ProjectUser &lt; ApplicationRecord
  belongs_to :project
  belongs_to :user
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.

class Project &lt; ApplicationRecord
  has_many :project_users, foreign_key: :project_id, inverse_of: :project
  has_many :users, through: :project_users
end

class User &lt; ApplicationRecord
  has_many :project_users, foreign_key: :user_id, inverse_of: :user
  has_many :projects, through: :project_users
end

class ProjectUser &lt; ApplicationRecord
  belongs_to :project
  belongs_to :user
end

答案2

得分: 0

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

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.

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

class User &lt; ApplicationRecord
  has_many :project_users
  has_many :projects, through: :project_users

  accepts_nested_attributes_for :projects
end

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

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

I believe that you need to use accepts_nested_attributes_for

class User &lt; ApplicationRecord
  has_many :project_users
  has_many :projects, through: :project_users

  accepts_nested_attributes_for :projects
end

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

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:

确定