有两个 model 为 has_one 和 belongs_to 关系:
class User < ApplicationRecord
has_one :second_review, dependent: :destroy
...
end
class SecondReview < ApplicationRecord
belongs_to :user
validates :user_id, presence: true, uniqueness: true
...
end
现在使用user.create_second_review!
来创建一条关联记录,如果user.second_review
已经存在的话,数据库会报错,然后删除旧的记录,但是不会插入新记录:
2.4.0 :036 > user.create_second_review!
(0.2ms) BEGIN
SecondReview Exists (0.3ms) SELECT 1 AS one FROM `second_reviews` WHERE `second_reviews`.`user_id` = 2 LIMIT 1
(0.1ms) ROLLBACK
(0.1ms) BEGIN
SQL (0.2ms) DELETE FROM `second_reviews` WHERE `second_reviews`.`id` = 12
(2.7ms) COMMIT
ActiveRecord::RecordInvalid: 验证失败: User已经被使用
from (irb):36
如果用 user.build_second_review.save!
,同样会删除旧的记录,但是会插入新的记录:
2.4.0 :038 > user.build_second_review.save!
(0.2ms) BEGIN
SQL (0.3ms) DELETE FROM `second_reviews` WHERE `second_reviews`.`id` = 13
(2.8ms) COMMIT
(0.2ms) BEGIN
SecondReview Exists (0.4ms) SELECT 1 AS one FROM `second_reviews` WHERE `second_reviews`.`user_id` = 2 LIMIT 1
SQL (0.3ms) INSERT INTO `second_reviews` (`user_id`, `created_at`, `updated_at`) VALUES (2, '2018-04-21 08:41:17', '2018-04-21 08:41:17')
(2.1ms) COMMIT
=> true
如果在 model 中去掉dependent: :destroy
,则不论是create
还是build.save
都不会有这种问题:
2.4.0 :003 > user.create_second_review!
(0.3ms) BEGIN
SecondReview Exists (0.4ms) SELECT 1 AS one FROM `second_reviews` WHERE `second_reviews`.`user_id` = 2 LIMIT 1
(0.1ms) ROLLBACK
(0.1ms) BEGIN
SecondReview Exists (0.4ms) SELECT 1 AS one FROM `second_reviews` WHERE `second_reviews`.`user_id` IS NULL AND (`second_reviews`.`id` != 22) LIMIT 1
(0.3ms) ROLLBACK
ActiveRecord::RecordNotSaved: Failed to remove the existing associated second_review. The record failed to save after its foreign key was set to nil.
from (irb):3
2.4.0 :004 > user.build_second_review.save!
(0.4ms) BEGIN
SecondReview Exists (0.4ms) SELECT 1 AS one FROM `second_reviews` WHERE `second_reviews`.`user_id` IS NULL AND (`second_reviews`.`id` != 22) LIMIT 1
(0.1ms) ROLLBACK
ActiveRecord::RecordNotSaved: Failed to remove the existing associated second_review. The record failed to save after its foreign key was set to nil.
from (irb):4
我的问题是:
1、既然 SecondReview 类里已经有 validation,为什么user_id
相同的时候依然会执行数据库操作(删掉旧记录)?
2、为什么create_second_review!
方法在删除旧的记录后不会插入新记录?
对于这个问题,如果 Rails 的机制就是这样的,是不是我就只能写诸如@user.create_second_review! if [email protected]_review
这样丑陋的代码?