我想重命名timestamp.rb中定义的timestamp列。 timestamp.rb的方法可以被覆盖吗?在应用程序中必须要做的事情是使用带有覆盖方法的模块。
答案 0 :(得分:25)
这可以通过编写ActiveRecord :: Timestamp模块方法来完成。实际上并没有覆盖整个模块。我需要在使用遗留数据库时实现同样的目标。我在轨道3上,我已经开始遵循一种方法,如何通过编写rails功能来修改我的代码。
我首先创建我正在使用的基础项目,并在初始化程序中创建一个名为this的文件。在这种情况下,我创建了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
注意:我还想提一下,这种用于让事情发挥作用的猴子补丁是不受欢迎的,可能会在升级时中断,所以要小心并充分意识到你是什么想做。
更新
答案 1 :(得分:24)
我认为NPatel的方法是一种正确的方法,但如果您只需要在单个模型上更改#created_at,它就会做得太多。由于Timestamp模块包含在每个AR对象中,因此您可以按模型覆盖它,而不是全局覆盖它。
< = Rails 5.0
class User < ActiveRecord::Base
...
private
def timestamp_attributes_for_create
super << :registered_at
end
end
Rails~&gt; 5.1
private_class_method
def self.timestamp_attributes_for_create
super << :registered_at
end
end
答案 2 :(得分:5)
您可以使用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
答案 3 :(得分:4)
没有简单的方法可以做到这一点。您可以通过覆盖ActiveRecord :: Timestamp模块,或者编写自己的模块来为您完成这项工作。
Here is魔法是如何运作的。
答案 4 :(得分:3)
快速丑陋的黑客,从Milan Novota的回答中详细说明:将以下内容附加到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
答案 5 :(得分:1)
在rails 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
答案 6 :(得分:1)
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
注意,如果您不想为所有模型配置它,也可以在特定模型上使用此模块。
请注意,而且您应该使用字符串而不是符号。
答案 7 :(得分:0)
或者您可以创建自己的列(DateTime),并在更新时创建并设置updated_at列时手动设置created_at列。这可能比上面的黑客更容易。这就是我要做的。更好的是,更新rails以允许我们更改这些名称。
答案 8 :(得分:0)
不使用猴子补丁的溶胶;在迁移过程中使用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
答案 9 :(得分:0)
在Rails 6.0中,实例方法timestamp_attributes_for_create
不再存在。该方法被推到类方法级别,现在是私有
https://apidock.com/rails/v6.0.0/ActiveRecord/Timestamp/ClassMethods/timestamp_attributes_for_create
此更改是通过此提交https://github.com/rails/rails/commit/77ff9a0adbd1318b45203a76c64561b115245603
引入的您仍然可以覆盖self.timestamp_attributes_for_create
,但是我强烈建议您不要这样做,因为可以在不另行通知或版本较大的情况下更改私有API。
对于Rails 6,我没有看到用于定义自定义created_at
/ updated_at
列的给定“轨道方法”。