如何使用其他方法扩展 ActiveRecord::Migration?

内容来源于 Stack Overflow,并遵循CC BY-SA 3.0许可协议进行翻译与使用

  • 回答 (2)
  • 关注 (0)
  • 查看 (59)

我正在创建一个Rubygem,并希望用我自己的帮助程序扩展ActiveRecord::Migration,以创建必要的列。我意识到我添加的功能本身非常琐碎,而且可能有更好/更有效的方法来实现这一点。

到目前为止,我已经成功地构建了一个GEM并安装了它,但是当我试图运行一个迁移时,如下所示:

class CreatePosts < ActiveRecord::Migration
  def self.up
    create_table :posts do |t|
      t.string :name
      t.string :title
      t.text :content
      t.hideable
      t.tracks_hidden_at
      t.timestamps
    end
  end
end

它说隐藏是没有定义的.

我做了以下工作:

扩展ActiveRecord,并添加了新的模型,并创建了一种基于新迁移方法应用模式更改的方法

require 'orm_adapter/adapters/active_record'

module HiddenRecord
  module Orm
    # This module contains some helpers and handle schema (migrations):
    #
    #   create_table :accounts do |t|
    #     t.hideable
    #     t.tracks_hidden_timestamp
    #   end
    #
    module ActiveRecord
      module Schema
        include HiddenRecord::Schema

        # Tell how to apply schema methods.
        def apply_hiddenrecord_schema(name, type, options={})
          column name, type.to_s.downcase.to_sym, options
        end
      end
    end
  end
end
ActiveRecord::Base.extend HiddenRecord::Models
ActiveRecord::ConnectionAdapters::Table.send :include, HiddenRecord::Orm::ActiveRecord::Schema
ActiveRecord::ConnectionAdapters::TableDefinition.send :include, HiddenRecord::Orm::ActiveRecord::Schema

创建了一个模式模块,类似于Design的schema.rb。

module HiddenRecord
  # Holds schema definition for hiddenrecord model options.
  module Schema
    # Sets the model as having hidable rows
    #
    # == Options
    # * :null - When true, allows the hidden row flag to be null
    # * :default - Used to set default hidden status to true. If not set, default is false (rows are not hidden)
    def hideable(options={})
      null = options[:null] || false
      default = options[:default] || false

      apply_hiddenrecord_schema :hiddenrecord_is_row_hidden, Boolean, :null => null, :default => default
    end

    # Sets the model to record the timestamp when a row was hidden
    def tracks_hidden_timestamp()
      apply_hiddenrecord_schema :hiddenrecord_hidden_at, DateTime
    end
  end
end

为支持新字段的模型添加了方法

module HiddenRecord
  module Models
    # This module implements the hideable API
    module Hideable
      def self.included(base)
        base.class_eval do
          extend ClassMethods
        end
      end

      scope :visible, where(:hiddenrecord_is_row_hidden => true)

      def hidden?
        return hiddenrecord_is_row_hidden || false
      end

      def hide
        hiddenrecord_is_row_hidden = true
      end

      def hide!
        hiddenrecord_is_row_hidden = true
        save!
      end

      def unhide
        hiddenrecord_is_row_hidden = false
      end

      def unhide!
        hiddenrecord_is_row_hidden = false
        save!
      end

    end
  end
end

加载模式和模型文件,并加载到gem的主模块中。

module HiddenRecord
  autoload :Schema, 'hiddenrecord/schema'
  autoload :Models, 'hiddenrecord/models'
  ...
end
require 'hiddenrecord/models/hideable'
require 'hiddenrecord/models/tracks_hidden_timestamp'

我希望有人能指出正确的方向,如何做到这一点。我正在Rails 3上尝试这个。

提问于
用户回答回答于

请注意,这些行:

ActiveRecord::ConnectionAdapters::Table.send :include, HiddenRecord::Orm::ActiveRecord::Schema
ActiveRecord::ConnectionAdapters::TableDefinition.send :include, HiddenRecord::Orm::ActiveRecord::Schema

我认为它们应该是:

ActiveRecord::ConnectionAdapters::Table.send :include, HiddenRecord::Schema
ActiveRecord::ConnectionAdapters::TableDefinition.send :include, HiddenRecord::Schema

但是,你似乎没有#tracks_hidden_at定义。

用户回答回答于

下面是我如何为以前的项目添加了Rails 2和MySQL的自定义迁移字段。效果很好。

我不知道这其中有多少符合你的具体需要,所以你可以随便问我一些问题。

我把这段代码放在Rails.root/lib/dbd_migration_helper.rb中

module Ddb

  module MigrationHelper

    def self.included(base) # :nodoc:
      base.send(:include, InstanceMethods)
    end

    module InstanceMethods
      def active    (column_name=:active)     column(column_name, :boolean, :default=>true) end
      def email     (column_name=:email)      column(column_name, :string)     end
      def latitude  (column_name=:latitude)   column(column_name, :float)      end
      def longitude (column_name=:longitude)  column(column_name, :float)      end
      def position  (column_name=:position)   column(column_name, :integer)    end
    end
  end
end

require 'activerecord'
if defined?(ActiveRecord::ConnectionAdapters::TableDefinition)
   ActiveRecord::ConnectionAdapters::TableDefinition.send(:include, Ddb::MigrationHelper)
end

扫码关注云+社区

领取腾讯云代金券