Переименование столбцов created_at, updated_at в ActiveRecord/Rails

Я хочу переименовать столбцы timestamp, определенные в timestamp.rb. Могут ли быть перезаписаны методы timestamp.rb? И что должно быть сделано в приложении, что модуль с перезаписанными методами используется.

Ответы

Ответ 1

Нет простого способа сделать это. Вы можете выполнить это либо путем переопределения модуля ActiveRecord:: Timestamp, либо путем написания собственного, чтобы сделать магию для вас.

Вот как работает волшебство.

Ответ 2

Это можно сделать, просто переписав методы модуля 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

ПРИМЕЧАНИЕ: я также хотел бы упомянуть, что такого рода исправления обезьян, чтобы заставить вещи работать, не одобряются и могут нарушать обновления, поэтому будьте осторожны и полностью осознайте, что именно вы хотите сделать.

Обновления:

  • Измените имена столбцов меток времени с символа на строку для каждого изменения API. Спасибо Techbrunch за то, что обратили на это внимание изменения API

Ответ 3

Я думаю, что метод 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

Ответ 4

Вы можете использовать методы 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

Ответ 5

быстрый уродливый взлом, исходя из ответа Милана Новота: добавьте следующее в 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

Ответ 6

Правильный синтаксис для этого в рельсах 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

Ответ 7

Обновленный ответ для 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

Обратите внимание, что вы также можете использовать этот блок для конкретной модели, если вы не хотите настраивать его для всех своих моделей.

Обратите внимание, что вы должны использовать строки, а не символы.

Ответ 8

Или вы можете просто создать свои собственные столбцы (DateTime) и просто вручную установить столбец created_at при создании и установке обновленного столбца при обновлении. Это может быть проще, чем взломать выше. Это то, что я собираюсь сделать. Еще лучше обновите рельсы, чтобы мы могли изменить эти имена.

Ответ 9

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