15

我想重命名 timestamp.rb 中定义的时间戳列。timestamp.rb 的方法可以被覆盖吗?以及在使用具有覆盖方法的模块的应用程序中必须做什么。

4

10 回答 10

28

我认为 NPatel 的方法是一种正确的方法,但如果您只需要在单个模型上更改 #created_at,它就做得太多了。由于 Timestamp 模块包含在每个 AR 对象中,因此您可以按模型覆盖它,而不是全局覆盖它。

<= 导轨 5.0

class User < ActiveRecord::Base
  ...
  private
  def timestamp_attributes_for_create
    super << :registered_at
  end
end

导轨 ~> 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
于 2012-11-19T16:24:02.500 回答
25

这可以通过重写 ActiveRecord::Timestamp 模块方法来完成。实际上并没有覆盖整个模块。我需要完成与使用遗留数据库相同的目标。我在 Rails 3 上,我已经开始遵循一种方法,如何通过重写 rails 功能来修补我的代码。

我首先创建了我正在使用的基础项目,并在初始化程序中创建了一个名为该文件的文件。在这种情况下,我创建了 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 更改将时间戳列名称从符号更改为字符串。感谢 Techbrunch 让我注意到这个 API 更改。
于 2010-10-20T19:29:36.370 回答
7

Rails >= 5.1的更新anwser 。我建议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

请注意,如果您不想为所有模型配置此模块,也可以在特定模型上使用此模块。

另请注意,您应该使用字符串而不是符号。

于 2018-09-11T13:17:35.327 回答
6

您可以使用 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
于 2013-08-12T22:28:03.937 回答
3

快速丑陋的 hack,从 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
于 2009-04-09T16:22:13.057 回答
2

没有简单的方法可以做到这一点。您可以通过覆盖 ActiveRecord::Timestamp 模块或编写您自己的模块来为您实现这一点。

这是魔术的工作原理。

于 2009-04-09T10:33:01.143 回答
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
于 2018-02-13T09:38:43.693 回答
0

或者您可以创建自己的列 (DateTime),并在创建时手动设置 created_at 列,并在更新时设置 updated_at 列。这可能比上面的 hack 更容易。这就是我要做的。更好的是,更新 rails 以允许我们更改这些名称。

于 2010-07-09T19:37:55.253 回答
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
于 2015-08-02T21:53:15.603 回答
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,我没有看到给定的“Rails 方式”来定义自定义created_at/updated_at列。

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

于 2020-04-14T20:56:06.517 回答