簡體   English   中英

重命名 ActiveRecord/Rails 的 created_at、updated_at 列

[英]Renaming the created_at, updated_at columns of ActiveRecord/Rails

我想重命名 timestamp.rb 中定義的時間戳列。 可以覆蓋timestamp.rb的方法嗎? 以及在使用具有覆蓋方法的模塊的應用程序中必須做什么。

我認為 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

這可以通過編寫 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 變化。

Rails >= 5.1更新 anwser 我建議使用ApplicationRecord中默認可用的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

請注意,如果您不想為所有模型配置它,您也可以在特定模型上使用此模塊。

請注意,您應該使用字符串而不是符號。

您可以使用 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

快速丑陋的 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

沒有簡單的方法可以做到這一點。 您可以通過覆蓋 ActiveRecord::Timestamp 模塊或編寫自己的模塊來實現這一點。

這是魔法的工作原理。

在 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

一個不使用猴子補丁的sol'n; 在遷移期間使用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

或者,您可以創建自己的列 (DateTime),並在創建時手動設置 created_at 列並在更新時設置 updated_at 列。 這可能比上面的 hack 更容易。 這就是我要做的。 更好的是,更新 rails 以允許我們更改這些名稱。

在 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但我強烈建議不self.timestamp_attributes_for_create ,因為私有 API 可以在沒有進一步通知或更大版本顛簸的情況下更改。

對於 Rails 6,我沒有看到定義自定義created_at / updated_at列的給定“Rails 方式”。

我建議遵循這個答案https://stackoverflow.com/a/18197702/924050

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM