2010-11-21 10 views
17

Tworzę klejnotu Ruby i chciałbym rozszerzyć ActiveRecord :: Migration przy pomocy moich własnych pomocników do tworzenia niezbędnych kolumn. (Jest to podobne do tego, co tworzy Devise podczas tworzenia migracji dla ich różnych strategii uwierzytelniania.) Zdaję sobie sprawę, że dodawana przeze mnie funkcjonalność jest dość trywialna i prawdopodobnie istnieją lepsze/bardziej wydajne sposoby robienia tego - próbuję tego jako uczenie się, a nie jako coś praktycznego zastosowania. Chcę tylko zrozumieć, jak zrobić coś tak inwazyjnego, jak dodanie nowych możliwości migracji w Railsach.Jak rozszerzyć ActiveRecord :: Migration za pomocą dodatkowych metod?

Co mam dotąd buduje się gem pomyślnie i instaluje, ale gdy próbuję uruchomić migrację takiego:

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 

... to zawiedzie mówiąc, że hideable nie jest zdefiniowana.

Zajrzałem do tego, w jaki sposób Devise to zrobił i muszę przyznać, że jestem trochę zagubiony, ale próbowałem się z tym pogodzić. Zrobiłem następujący:

Rozszerzone ActiveRecord z moich nowych modeli dodatkami i stworzył metodę, aby zastosować zmiany schematu opartego na moich nowych metod migracji

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 

Utworzono moduł schematu podobnego do opracowania-tych schema.rb który definiuje metody chcę użyć w migracji i wywołuje metodę zastosować schemat

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 

Dodano metody modeli w celu wspierania nowych pól

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 

załadować pliki schematów i modeli oraz w głównym module gem

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

Ponownie, uznając, że jest to przede wszystkim uczenie się, mam nadzieję, że ktoś może wskazać mi właściwy kierunek, jak to zrobić. Próbuję to na Rails 3.

+0

Nawiasem mówiąc, jeśli używasz tego do DRY up kodu w migracji, może zwrócić uwagę na zapach kodu, ponieważ powtarzają pola w całym modelu danych.Może to oznaczać, że powinieneś znormalizować swój model danych, aby ograniczyć duplikowanie. – BlueFish

Odpowiedz

5

Oto jak dodałem niestandardowe pola migracji z Rails 2 i MySQL dla poprzedniego projektu. Działa świetnie.

Nie wiem, jak wiele z tego dotyczy Twojej konkretnej potrzeby, więc możesz zadawać mi pytania.

umieścić ten kod w 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

Szybka uwaga, te linie:

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

nie wydają się być include'ing właściwy moduł . Myślę, że powinny one być:

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

ale potem, nie wydaje się mieć #tracks_hidden_at nigdzie zdefiniowane albo.

Powiązane problemy