使用 `assign_attributes` 立即保存 `has_many through:` 关联
Using `assign_attributes` saves `has_many through:` association immediately
据我所知,assign_attributes
(与 update_attributes
不同)不应该保存记录或任何记录。
所以当我发现为 has_many through:
关系提供 _ids
时情况并非如此时,我感到非常震惊。
考虑以下示例:
class GroupUser < ApplicationRecord
belongs_to :group
belongs_to :user
end
class Group < ApplicationRecord
has_many :group_users
has_many :users, through: :group_users
end
class User < ApplicationRecord
has_many :group_users
has_many :groups, through: :group_users
validates :username, presence: true
end
所以我们的用户和组之间存在多对多关系。
Group.create # Create group with ID 1
Group.create # Create group with ID 2
u = User.create(username: 'Johny')
# The following line inserts two `GroupUser` join objects, despite the fact
# that we have called `assign_attributes` instead of `update_attributes`
# and, equally disturbing, the user object is not even valid as we've
# supplied an empty `username` attribute.
u.assign_attributes(username: '', group_ids: [1, 26])
评论者要求的日志:
irb(main):013:0> u.assign_attributes(username: '', group_ids: [1, 2])
Group Load (0.2ms) SELECT "groups".* FROM "groups" WHERE "groups"."id" IN (1, 2)
Group Load (0.1ms) SELECT "groups".* FROM "groups" INNER JOIN "group_users" ON "groups"."id" = "group_users"."group_id" WHERE "group_users"."user_id" = ? [["user_id", 1]]
(0.0ms) begin transaction
SQL (0.3ms) INSERT INTO "group_users" ("group_id", "user_id", "created_at", "updated_at") VALUES (?, ?, ?, ?) [["group_id", 1], ["user_id", 1], ["created_at", "2017-06-29 08:15:11.691941"], ["updated_at", "2017-06-29 08:15:11.691941"]]
SQL (0.1ms) INSERT INTO "group_users" ("group_id", "user_id", "created_at", "updated_at") VALUES (?, ?, ?, ?) [["group_id", 2], ["user_id", 1], ["created_at", "2017-06-29 08:15:11.693984"], ["updated_at", "2017-06-29 08:15:11.693984"]]
(2.5ms) commit transaction
=> nil
我敢说 update_attributes
和 _ids
构造主要用于处理 Web 表单 - 在本例中是更新用户本身及其组关联的表单。所以我认为可以很安全地说这里的一般假设是 all or nothing,而不是部分保存。
我是不是用错了?
@gokul-m 建议在 https://github.com/rails/rails/issues/17368. One of the comments in there points to a temporary workaround: https://gist.github.com/remofritzsche/4204e399e547ff7e3afdd0d89a5aaf3e
阅读有关该问题的信息
我解决这个问题的一个例子:
ruby:
def assign_parameters(attributes, options = {})
with_transaction_returning_status {self.assign_attributes(attributes, options)}
end
您可以像这样使用 assign_attributes 处理验证
@item.assign_attributes{ year: "2021", type: "bad" }.valid?
据我所知,assign_attributes
(与 update_attributes
不同)不应该保存记录或任何记录。
所以当我发现为 has_many through:
关系提供 _ids
时情况并非如此时,我感到非常震惊。
考虑以下示例:
class GroupUser < ApplicationRecord
belongs_to :group
belongs_to :user
end
class Group < ApplicationRecord
has_many :group_users
has_many :users, through: :group_users
end
class User < ApplicationRecord
has_many :group_users
has_many :groups, through: :group_users
validates :username, presence: true
end
所以我们的用户和组之间存在多对多关系。
Group.create # Create group with ID 1
Group.create # Create group with ID 2
u = User.create(username: 'Johny')
# The following line inserts two `GroupUser` join objects, despite the fact
# that we have called `assign_attributes` instead of `update_attributes`
# and, equally disturbing, the user object is not even valid as we've
# supplied an empty `username` attribute.
u.assign_attributes(username: '', group_ids: [1, 26])
评论者要求的日志:
irb(main):013:0> u.assign_attributes(username: '', group_ids: [1, 2])
Group Load (0.2ms) SELECT "groups".* FROM "groups" WHERE "groups"."id" IN (1, 2)
Group Load (0.1ms) SELECT "groups".* FROM "groups" INNER JOIN "group_users" ON "groups"."id" = "group_users"."group_id" WHERE "group_users"."user_id" = ? [["user_id", 1]]
(0.0ms) begin transaction
SQL (0.3ms) INSERT INTO "group_users" ("group_id", "user_id", "created_at", "updated_at") VALUES (?, ?, ?, ?) [["group_id", 1], ["user_id", 1], ["created_at", "2017-06-29 08:15:11.691941"], ["updated_at", "2017-06-29 08:15:11.691941"]]
SQL (0.1ms) INSERT INTO "group_users" ("group_id", "user_id", "created_at", "updated_at") VALUES (?, ?, ?, ?) [["group_id", 2], ["user_id", 1], ["created_at", "2017-06-29 08:15:11.693984"], ["updated_at", "2017-06-29 08:15:11.693984"]]
(2.5ms) commit transaction
=> nil
我敢说 update_attributes
和 _ids
构造主要用于处理 Web 表单 - 在本例中是更新用户本身及其组关联的表单。所以我认为可以很安全地说这里的一般假设是 all or nothing,而不是部分保存。
我是不是用错了?
@gokul-m 建议在 https://github.com/rails/rails/issues/17368. One of the comments in there points to a temporary workaround: https://gist.github.com/remofritzsche/4204e399e547ff7e3afdd0d89a5aaf3e
阅读有关该问题的信息我解决这个问题的一个例子:
ruby:
def assign_parameters(attributes, options = {})
with_transaction_returning_status {self.assign_attributes(attributes, options)}
end
您可以像这样使用 assign_attributes 处理验证
@item.assign_attributes{ year: "2021", type: "bad" }.valid?