ruby on rails - run - ¿Cómo extender ActiveRecord:: Migration con métodos adicionales?
ruby on rails run migrations (2)
Estoy creando una gema de Ruby y me gustaría extender ActiveRecord :: Migration con mis propios ayudantes para crear las columnas necesarias. (Esto es similar a lo que hace Devise al crear migraciones para sus diversas estrategias de autenticación). Me doy cuenta de que la funcionalidad que estoy agregando es bastante trivial en sí misma y probablemente haya formas mejores / más eficientes de hacer esto. Estoy intentando esto como un Experiencia de aprendizaje en lugar de como algo con aplicación práctica. Solo quiero entender cómo hacer algo tan invasivo como agregar nuevas capacidades de migración en Rails.
Lo que tengo hasta ahora se convierte en una gema con éxito y se instala, pero cuando intento ejecutar una migración como:
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
... falla diciendo que no se puede definir lo que se puede ocultar.
He investigado la forma en que Devise ha hecho esto y tengo que admitir que estoy un poco perdido, pero he intentado buscarlo. He hecho lo siguiente:
Extended ActiveRecord con mis nuevas incorporaciones de modelo y creó un método para aplicar los cambios de esquema basados en mis nuevos métodos de migración
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
Creé un módulo de esquema similar al esquema de Devise.rb que define los métodos que quiero usar en la migración y llama a un método para aplicar el esquema.
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
Métodos añadidos para que los modelos soporten los nuevos campos.
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
Cargue los archivos de esquema y modelo y en el módulo principal de la gema.
module HiddenRecord
autoload :Schema, ''hiddenrecord/schema''
autoload :Models, ''hiddenrecord/models''
...
end
require ''hiddenrecord/models/hideable''
require ''hiddenrecord/models/tracks_hidden_timestamp''
Una vez más, reconociendo que esto es principalmente una experiencia de aprendizaje, espero que alguien pueda orientarme en la dirección correcta sobre cómo hacer esto. Estoy intentando esto en Rails 3.
Así es como agregué campos de migración personalizados con Rails 2 y MySQL para un proyecto anterior. Funciona genial.
No sé cuánto de esto se aplica a su necesidad exacta, así que no dude en hacerme preguntas.
Puse este código en 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
Nota rápida, estas líneas:
ActiveRecord::ConnectionAdapters::Table.send :include, HiddenRecord::Orm::ActiveRecord::Schema
ActiveRecord::ConnectionAdapters::TableDefinition.send :include, HiddenRecord::Orm::ActiveRecord::Schema
No parece estar incluyendo el módulo correcto. Creo que deberían ser:
ActiveRecord::ConnectionAdapters::Table.send :include, HiddenRecord::Schema
ActiveRecord::ConnectionAdapters::TableDefinition.send :include, HiddenRecord::Schema
pero entonces, tampoco parece tener #tracks_hidden_at
definido en ninguna parte.