Rails версия: 5.2.2.1
Хотите вставить или обновить данные в post_copies
, когда title
данные в posts
изменились с нуля на реальные данные.
Что я пробовал:
Модель
class Post < ApplicationRecord
after_save :save_post_copy
private
def save_post_copy
if will_save_change_to_title? == nil and saved_change_to_title?
post_copy = PostCopy.find_by(id: self.id)
if post_copy.nil?
PostCopy.create!(id: self.id, title: self.title, body: self.body)
else
post_copy.update!(title: self.title, body: self.body)
end
end
end
end
Консоль
Случай 1: Обновление данных с нуля до не ноль
post = Post.new
=> #<Post id: nil, title: nil, body: nil, created_at: nil, updated_at: nil>
post.body = 'test'
=> "test"
post.save!
(0.1ms) begin transaction
Post Create (0.9ms) INSERT INTO "posts" ("body", "created_at", "updated_at") VALUES (?, ?, ?) [["body", "test"], ["created_at", "2019-05-20 07:19:50.289983"], ["updated_at", "2019-05-20 07:19:50.289983"]]
(6.5ms) commit transaction
=> true
post.title = '3'
=> '3'
post.save!
(0.1ms) begin transaction
Post Update (0.5ms) UPDATE "posts" SET "title" = ?, "updated_at" = ? WHERE "posts"."id" = ? [["title", "3"], ["updated_at", "2019-05-20 07:20:04.138089"], ["id", 8]]
PostCopy Load (0.1ms) SELECT "post_copies".* FROM "post_copies" WHERE "post_copies"."id" = ? LIMIT ? [["id", 8], ["LIMIT", 1]]
PostCopy Create (0.3ms) INSERT INTO "post_copies" ("title", "body", "created_at", "updated_at") VALUES (?, ?, ?, ?) [["title", "3"], ["body", "test"], ["created_at", "2019-05-20 07:20:04.148852"], ["updated_at", "2019-05-20 07:20:04.
148852"]]
(7.1ms) commit transaction
=> true
Случай 2: Обновление данных не из ноля в ноль
post
=> #<Post id: 10, title: "ten", body: "10", created_at: "2019-05-20 07:21:08", updated_at: "2019-05-20 07:21:41">
post.title = nil
post.save!
(0.1ms) begin transaction
Post Update (1.4ms) UPDATE "posts" SET "title" = ?, "updated_at" = ? WHERE "posts"."id" = ? [["title", nil], ["updated_at", "2019-05-20 07:34:15.594000"], ["id", 10]]
PostCopy Load (0.1ms) SELECT "post_copies".* FROM "post_copies" WHERE "post_copies"."id" = ? LIMIT ? [["id", 10], ["LIMIT", 1]]
PostCopy Create (0.3ms) INSERT INTO "post_copies" ("body", "created_at", "updated_at") VALUES (?, ?, ?) [["body", "10"], ["created_at", "2019-05-20 07:34:15.598453"], ["updated_at", "2019-05-20 07:34:15.598453"]]
(1.8ms) commit transaction
=> true
Случай 3: Обновление данных с не ноль на не ноль (другое)
post
=> #<Post id: 10, title: "ten", body: "10", created_at: "2019-05-20 07:21:08", updated_at: "2019-05-20 07:21:41">
post.will_save_change_to_title?
=> nil
post.title = '1'
=> "1"
post.will_save_change_to_title?
=> true
post.save!
(0.1ms) begin transaction
Post Update (0.6ms) UPDATE "posts" SET "title" = ?, "updated_at" = ? WHERE "posts"."id" = ? [["title", "1"], ["updated_at", "2019-05-20 07:37:46.467899"], ["id", 10]]
PostCopy Load (0.1ms) SELECT "post_copies".* FROM "post_copies" WHERE "post_copies"."id" = ? LIMIT ? [["id", 10], ["LIMIT", 1]]
PostCopy Update (0.3ms) UPDATE "post_copies" SET "title" = ?, "updated_at" = ? WHERE "post_copies"."id" = ? [["title", "1"], ["updated_at", "2019-05-20 07:37:46.471654"], ["id", 10]]
(1.3ms) commit transaction
=> true
Случай 2 и случай 3 инициируют сохранение / обновление до действия post_copies
. Таким образом, will_save_change_to_title? == nil
не может знать, что данные изменяются с ноля на ноль.
Отсюда:
https://api.rubyonrails.org/classes/ActiveModel/Dirty.html
Есть эти методы:
person = Person.new
person.changed? # => false
person.name = 'Bob'
person.changed? # => true
person.name_changed? # => true
person.name_changed?(from: nil, to: "Bob") # => true
person.name_was # => nil
person.name_change # => [nil, "Bob"]
person.name = 'Bill'
person.name_change # => [nil, "Bill"]
Но, кажется, не существует в will_save_change_to_title
.