-
Notifications
You must be signed in to change notification settings - Fork 22.2k
Description
Steps to reproduce
1. Create a model
class Order < ApplicationRecord
end2. Create a migration with a DB function as default.
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
endrails 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
> 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 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 useRETURNING *instead.
This blog post describes the issue wonderfully.
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