Adding timestamps to an existing table with Ecto's timestamps

雨燕双飞 提交于 2019-12-07 01:21:23

问题


This has been asked here How to add timestamps to an existing table with Ecto's timestamps?, however the accepted solution means that every new entry will have the same default time. I would want the new entries to have the correct time of insert/update.

eg.

# set default to given date to fill in all existing rows with timestamps
def change do
  alter table(:my_table) do
   timestamps(default: "2018-01-01 00:00:01")
  end
end

If this is all that is in the migration, every inserted_at and updated_at for :my_table will have 2018-01-01 00:00:01 as the value, regardless of the date it was inserted/updated.

What I want to do is:

  1. Add datetime to inserted_at & updated_at columns for pre-existing rows.
  2. inserted_at and updated_at should be null: false as they are when adding timestamps to a newly created table.
  3. Future entries should have the correct inserted_at and updated_at values i.e. inserted_at is the time the row was made, and updated_at is the time it was changed, instead of the default set in the migration.

I had a couple of solutions that do achieve this, but they seem quite messy. I am looking if there is a cleaner way to do this, or if there are options to handle this case which I am missing.

Working migration 1:

def up do
  alter table(:my_table) do
    timestamps(default: "now()")
  end
  execute("ALTER TABLE my_table ALTER COLUMN inserted_at SET DEFAULT now()")
  execute("ALTER TABLE my_table ALTER COLUMN updated_at SET DEFAULT now()")
end

def down do
  alter table(:my_table) do
    remove :inserted_at
    remove :updated_at
  end
end

Working migration 2:

def up do
  alter table(:my_table) do
    timestamps(null: true)
  end
  execute("UPDATE my_table SET inserted_at = now()")
  execute("UPDATE my_table SET updated_at = now()")
  alter table(:my_table) do
    modify :inserted_at, :naive_datetime, null: false
    modify :updated_at, :naive_datetime, null: false
  end
end

def down do
  alter table(:my_table) do
    remove :inserted_at
    remove :updated_at
  end
end

回答1:


I ran into the same issue. For me, this was dued to not specifying timestamps() in the Ecto schema:

schema "my_table" do
    field(:name, :string)
    ...
    timestamps() // <- Add this here
end

The migration just tells your DB that you have timestamps columns. You still need to tell Ecto that they exist!



来源:https://stackoverflow.com/questions/49516123/adding-timestamps-to-an-existing-table-with-ectos-timestamps

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!