2010-11-21 17 views
17

Sto creando una gemma Ruby e vorrei estendere ActiveRecord :: Migration con i miei aiutanti per creare le colonne necessarie. (Questo è simile a ciò che Devise fa quando crea le migrazioni per le loro varie strategie di autenticazione.) Mi rendo conto che la funzionalità che sto aggiungendo è piuttosto banale e ci sono probabilmente modi migliori/più efficienti per farlo - sto provando questo esperienza di apprendimento piuttosto che come qualcosa con applicazione pratica. Voglio solo capire come fare qualcosa di così invasivo come aggiungere nuove funzionalità di migrazione in Rails.Come estendere ActiveRecord :: Migration con metodi aggiuntivi?

Quello che ho costruisce finora in un gioiello con successo e monta, ma quando si tenta di eseguire una migrazione simile:

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 

... fallisce dicendo che hideable non è definito.

Ho esaminato il modo in cui Devise ha fatto questo e devo ammettere che sono un po 'perso, ma ho cercato di armeggiare. Ho fatto quanto segue:

esteso ActiveRecord con le mie nuove aggiunte modello e ha creato un metodo per applicare le modifiche dello schema in base alle mie nuove metodologie di migrazione

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 

Creato un modulo schema simile di escogitare di schema.rb che definisce i metodi che voglio utilizzare nella migrazione e chiama un metodo per applicare lo schema

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 

metodi aggiunto per i modelli per supportare i nuovi campi

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 

Caricare i file di schema e il modello e il modulo principale della gemma

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

Anche in questo caso, riconoscendo che questo è soprattutto un esperienza di apprendimento, spero che qualcuno possa indicarmi la giusta direzione su come farlo. Lo sto provando su Rails 3.

+0

Per inciso, se si sta utilizzando questo per ASCIUGARE il codice nelle migrazioni, potrebbe segnalare un odore di codice perché si stanno ripetendo i campi nel modello di dati.Potrebbe indicare che è necessario normalizzare il modello di dati per ridurre la duplicazione. – BlueFish

risposta

5

Ecco come ho aggiunto campi di migrazione personalizzati con Rails 2 e MySQL per un progetto precedente. Funziona alla grande.

Non so quanto questo si applichi all'esatta necessità, quindi sentitevi liberi di farmi domande.

ho messo questo codice in 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 
2

nota rapida, queste righe:

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

non sembrano essere include'ing il modulo corretto . Penso che dovrebbero essere:

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

ma poi, non sembrano avere #tracks_hidden_at definito da nessuna parte neanche.

Problemi correlati