Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- ### Steps to reproduce
- **1. Create a model**
- ```Ruby
- class Order < ApplicationRecord
- end
- ```
- **2. Create a migration with a DB function as `default`.**
- ```Ruby
- class CreateOrders < ActiveRecord::Migration[5.2]
- def change
- create_table :orders do |t|
- t.string :uuid, default: -> { "gen_random_uuid()" }
- t.references :user
- t.references :product
- t.text :comment
- t.timestamps
- end
- end
- end
- ```
- `rails db:migrate`
- **3. Create a new order**
- `rails console`
- ```
- order = Order.create(user_id: 1, product_id: 1)
- ```
- ### Expected behavior
- I expect `create` to set `uuid` (by the postgres default) **and** for it to set the new `uuid` value into the `order` AR instance, as it does with the `id`.
- ```
- > order
- # =>
- # +----+--------------------------------------+---------+------------+---------+----------------+----------------+
- # | id | uuid | user_id | product_id | comment | created_at | updated_at |
- # +----+--------------------------------------+---------+------------+---------+----------------+----------------+
- # | 1 | bec94fe0-f7c3-4ede-8b25-c4bce702ec00 | 1 | 1 | | 2018-10-17 ... | 2018-10-17 ... |
- # +----+--------------------------------------+---------+------------+---------+----------------+----------------+
- ```
- ### Actual behavior
- The `uuid` does get set in the db, but it is not returned into the `order` instance.
- ```
- > order
- # =>
- # +----+------+---------+------------+---------+----------------+----------------+
- # | id | uuid | user_id | product_id | comment | created_at | updated_at |
- # +----+------+---------+------------+---------+----------------+----------------+
- # | 1 | | 1 | 1 | | 2018-10-17 ... | 2018-10-17 ... |
- # +----+------+---------+------------+---------+----------------+----------------+
- ```
- ### Current workaround
- Calling `order.reload` does then retrieve the values set by postgres. Other workarounds are [described in this issue](https://github.com/rails/rails/issues/21627)
- ```
- > order
- # =>
- # +----+--------------------------------------+---------+------------+---------+----------------+----------------+
- # | id | uuid | user_id | product_id | comment | created_at | updated_at |
- # +----+--------------------------------------+---------+------------+---------+----------------+----------------+
- # | 1 | bec94fe0-f7c3-4ede-8b25-c4bce702ec00 | 1 | 1 | | 2018-10-17 ... | 2018-10-17 ... |
- # +----+--------------------------------------+---------+------------+---------+----------------+----------------+
- ```
- ### Background
- [This issue already describes](https://github.com/rails/rails/issues/21627) this bug, but the issue was initially a request to support functional defaults, which has since been implemented.
- This quote from the discussion summarizes it pretty well:
- > @kenaniah Sure, but it makes sense why the full row shouldn't be returned by default: there could be too much data, and ActiveRecord already knows both default and non-default values. (Or at least it thinks so.) But if the default value is generated by a function in PG then ActiveRecord doesn't know. Turns out that is not enough reason to make `RETURNING *` the default, and I'm ok with that. I think what we need is another parameter to tell ActiveRecord, that for a particular model, it should use `RETURNING *` instead.
- This blog post [describes the issue wonderfully](https://www.devmynd.com/blog/db-generated-values-and-activerecord/).
- ### Next steps
- So a solution could be an option to tell AR to use `RETURNING *` in some instances. But I myself am not familiar with the ActiveRecord internals so I feel this should be further discussed.
- ### System configuration
- **Rails version**: 5.2.1
- **Ruby version**: 2.4.1
- **Postgres version**: 9.6.3
Add Comment
Please, Sign In to add comment