重命名ActiveRecord / Rails的created_at,updated_at列

时间:2009-04-09 10:20:07

标签: ruby-on-rails activerecord timestamp

我想重命名timestamp.rb中定义的timestamp列。 timestamp.rb的方法可以被覆盖吗?在应用程序中必须要做的事情是使用带有覆盖方法的模块。

10 个答案:

答案 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

注意:我还想提一下,这种用于让事情发挥作用的猴子补丁是不受欢迎的,可能会在升级时中断,所以要小心并充分意识到你是什么想做。

更新

  • 根据api change将时间戳列名从符号更改为字符串。感谢Techbrunch将此API更改引起我的注意。

答案 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列的给定“轨道方法”。

我建议遵循此答案https://stackoverflow.com/a/18197702/924050