diff --git a/README.md b/README.md index a6348b3..185e133 100644 --- a/README.md +++ b/README.md @@ -10,7 +10,7 @@ pairing with smart people at Hashrocket. For a steady stream of TILs, [sign up for my newsletter](https://crafty-builder-6996.ck.page/e169c61186). -_1648 TILs and counting..._ +_1649 TILs and counting..._ See some of the other learning resources I work on: - [Get Started with Vimium](https://egghead.io/courses/get-started-with-vimium~3t5f7) @@ -1083,6 +1083,7 @@ If you've learned something here, support my efforts writing daily TILs by - [Make A String Attribute Easy To Inquire About](rails/make-a-string-attribute-easy-to-inquire-about.md) - [Make ActionMailer Synchronous In Test](rails/make-action-mailer-synchronous-in-test.md) - [Make Remove Column Migration Reversible](rails/make-remove-column-migration-reversible.md) +- [Manage Timestamps With Upsert](rails/manage-timestamps-with-upsert.md) - [Manually Run A Migration From Rails Console](rails/manually-run-a-migration-from-rails-console.md) - [Mark For Destruction](rails/mark-for-destruction.md) - [Mask An ActiveRecord Attribute](rails/mask-an-activerecord-attribute.md) diff --git a/rails/manage-timestamps-with-upsert.md b/rails/manage-timestamps-with-upsert.md new file mode 100644 index 0000000..3495131 --- /dev/null +++ b/rails/manage-timestamps-with-upsert.md @@ -0,0 +1,55 @@ +# Manage Timestamps With Upsert + +Modern versions of Rails and ActiveRecord have [an `upsert` +method](https://api.rubyonrails.org/v8.0.2/classes/ActiveRecord/Relation.html#method-i-upsert) +which will, if available, use your database's upsert capability to either +insert a new row or update an existing row based on the unique identifier. + +The docs have the following disclaimer: + +> It does not instantiate any models nor does it trigger Active Record +> callbacks or validations. Though passed values go through Active Record’s +> type casting and serialization. + +It's a bit different to work with than other ActiveRecord methods. It left me +wondering if it would handle timestamp management or if I would have to do that +myself. + +Let's upsert a new record into `books`: + +```ruby +> Book.upsert({title: "Shogun", author: "James Clavell", added_by_id: 1, publication_date: Date.today}, unique_by: :id) +=> # Book.select(:id, :title, :created_at, :updated_at).last +=> # +``` + +Notice that the `created_at` and `updated_at` timestamps get set. + +Now, let's upsert the record (notice we're passing in the `id`) to update the title with an `ō`. + +```ruby +> Book.upsert({id: 12, title: "Shōgun", author: "James Clavell", added_by_id: 1, publication_date: Date.today}, unique_by: :id) +=> # Book.select(:id, :title, :created_at, :updated_at).last +=> # +``` + +Notice that the `updated_at` gets set to a time about 2 minutes later. + +Lastly let's look at the `record_timestamps` option. This is `nil` by default +which means the underlying methods default kicks in which _is_ to record the +timestamps. We can override that behavior by passing in `false`. + +```ruby +> Book.upsert({id: 12, title: "Shōgun, Part 2", author: "James Clavell", added_by_id: 1, publication_date: Date.today}, unique_by: :id, record_timestamps: false) +=> # Book.select(:id, :title, :created_at, :updated_at).last +=> # +``` + +Notice that the `updated_at` value doesn't change between this upsert and the +previous upsert.