Ответ 1
Нет простого способа сделать это. Вы можете выполнить это либо путем переопределения модуля ActiveRecord:: Timestamp, либо путем написания собственного, чтобы сделать магию для вас.
Я хочу переименовать столбцы timestamp, определенные в timestamp.rb. Могут ли быть перезаписаны методы timestamp.rb? И что должно быть сделано в приложении, что модуль с перезаписанными методами используется.
Нет простого способа сделать это. Вы можете выполнить это либо путем переопределения модуля ActiveRecord:: Timestamp, либо путем написания собственного, чтобы сделать магию для вас.
Это можно сделать, просто переписав методы модуля ActiveRecord :: Timestamp. На самом деле не перезаписывает весь модуль. Мне нужно для достижения этой же цели, так как я работаю с устаревшей базой данных. Я нахожусь на рельсах 3, и я начал следовать методологии, как обезопасить мой код с перезаписью функциональности рельсов.
Сначала я создаю базовый проект, с которым я работаю, и создаю файл с именем этого в инициализаторах. В этом случае я создал active_record.rb. И внутри файла я поместил код для переопределения двух методов, которые контролировали метку времени. Ниже приведен пример моего кода:
module ActiveRecord
module Timestamp
private
def timestamp_attributes_for_update #:nodoc:
["updated_at", "updated_on", "modified_at"]
end
def timestamp_attributes_for_create #:nodoc:
["created_at", "created_on"]
end
end
end
ПРИМЕЧАНИЕ: я также хотел бы упомянуть, что такого рода исправления обезьян, чтобы заставить вещи работать, не одобряются и могут нарушать обновления, поэтому будьте осторожны и полностью осознайте, что именно вы хотите сделать.
Обновления:
Я думаю, что метод NPatel является правильным подходом, но он делает слишком много, если вам нужно только изменить #created_at в одной модели. Поскольку модуль Timestamp включен в каждый объект AR, вы можете просто переопределить его для каждой модели, а не глобально.
<= Rails 5.0
class User < ActiveRecord::Base
...
private
def timestamp_attributes_for_create
super << :registered_at
end
end
Rails ~> 5.1
private_class_method
def self.timestamp_attributes_for_create
# only strings allowed here, symbols won't work, see below commit for more details
# https://github.com/rails/rails/commit/2b5dacb43dd92e98e1fd240a80c2a540ed380257
super << 'registered_at'
end
end
Вы можете использовать методы beforesave и beforecreate для публикации DateTime.now в указанных столбцах.
class Sample < ActiveRecord::Base
before_create :set_time_stamps
before_save :set_time_stamps
private
def set_time_stamps
self.created_column = DateTime.now if self.new_record?
self.updated_column = DateTime.now
end
end
быстрый уродливый взлом, исходя из ответа Милана Новота: добавьте следующее в environment.rb, заменив значения констант CREATED_COL и UPDATED_COL на нужные имена столбцов:
module ActiveRecord
module Timestamp
CREATED_COL = 'created_at'
UPDATED_COL = 'updated_at'
private
def create_with_timestamps #:nodoc:
if record_timestamps
t = self.class.default_timezone == :utc ? Time.now.utc : Time.now
write_attribute(CREATED_COL, t) if respond_to?(CREATED_COL) && send(CREATED_COL).nil?
write_attribute(UPDATED_COL, t) if respond_to?(UPDATED_COL) && send(UPDATED_COL).nil?
end
create_without_timestamps
end
def update_with_timestamps(*args) #:nodoc:
if record_timestamps && (!partial_updates? || changed?)
t = self.class.default_timezone == :utc ? Time.now.utc : Time.now
write_attribute(UPDATED_COL, t) if respond_to?(UPDATED_COL)
end
update_without_timestamps(*args)
end
end
end
Правильный синтаксис для этого в рельсах 4.2
class User < ActiveRecord::Base
...
private
def timestamp_attributes_for_create
super << 'date_add'
end
def timestamp_attributes_for_update
super << 'date_update'
end
end
Обновленный ответ для Rails> = 5.1. Я бы предложил использовать ApplicationRecord
который доступен по умолчанию в вашем приложении, и определить следующее:
class ApplicationRecord < ActiveRecord::Base
self.abstract_class = true
class << self
private
def timestamp_attributes_for_create
super << 'my_created_at_column'
end
def timestamp_attributes_for_update
super << 'my_updated_at_column'
end
end
end
Обратите внимание, что вы также можете использовать этот блок для конкретной модели, если вы не хотите настраивать его для всех своих моделей.
Обратите внимание, что вы должны использовать строки, а не символы.
Или вы можете просто создать свои собственные столбцы (DateTime) и просто вручную установить столбец created_at при создании и установке обновленного столбца при обновлении. Это может быть проще, чем взломать выше. Это то, что я собираюсь сделать. Еще лучше обновите рельсы, чтобы мы могли изменить эти имена.
Soln, который не использует патч обезьяны; используйте блок reversible
во время миграции:
class CreateTest < ActiveRecord::Migration
def change
create_table :test do |t|
end
# set the timestamp columns default to now()
reversible do |dir|
dir.up do
tables = [
:test
]
tables.each do |t|
execute <<-SQL
ALTER TABLE #{t.to_s}
add column created timestamp without time zone default now();
SQL
execute <<-SQL
ALTER TABLE #{t.to_s}
add column updated timestamp without time zone default now();
SQL
end
end
dir.down do
# no need to do anything, the rollback will drop the tables
end
end
end
end