Как сохранить в другую таблицу, когда одна запись одной таблицы изменилась с ноль на ноль с Rails? - PullRequest
0 голосов
/ 20 мая 2019

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.

1 Ответ

1 голос
/ 20 мая 2019

Я думаю, что ваша проблема в использовании "after_save": попробуйте вместо этого использовать "before_save".

РЕДАКТИРОВАТЬ: Хорошо, я попробовал это и сейчас, и после того, как я понял, что это не работает, я проверил вашу ссылку: не похоже, что вы сделали то, что требуется для реализации этих методов.

Все указано в верхней части страницы:

The requirements for implementing ActiveModel::Dirty are:

include ActiveModel::Dirty in your object.

Call define_attribute_methods passing each method you want to track.

Call [attr_name]_will_change! before each change to the tracked attribute.

Call changes_applied after the changes are persisted.

Call clear_changes_information when you want to reset the changes information.

Call restore_attributes when you want to restore previous data.

Попробуйте следовать этим инструкциям и примеру.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...