2009-03-29 2 views
28

Ich möchte ein Enum Feld bei sone Migration schaffen, aber ich kann den Weg nicht finden, um es in derWie (Ersetzung | Erstellen) ein Enum-Feld auf Schienen 2.0 Migrationen? Ich mache, habe ich versucht in Google suchen

das einzige, was ich war

gefunden Migration zu tun
t.column :status, :enum, :limit => [:accepted, :cancelled, :pending] 

aber sieht aus wie der obige Code nur auf Schienen läuft 1.xxx und da ich Schienen 2.0

läuft das, was ich versucht, aber es funktioniert nicht

class CreatePayments < ActiveRecord::Migration 
    def self.up 
    create_table :payments do |t| 
     t.string :concept 
     t.integer :user_id 
     t.text :notes 
     t.enum :status, :limit => [:accepted, :cancelled, :pending] 

     t.timestamps 
    end 
    end 

    def self.down 
    drop_table :payments 
    end 
end 

Also, falls das nicht erlaubt ist, was könnte Ihrer Meinung nach eine gute Lösung sein? nur ein Textfeld und Validierung aus dem Modell?

+0

Ich weiß, dass es eine lange Zeit her ist, seit Ihrer Frage gestellt wurde und dass es für Schienen 2.0 gemeint. Aber ich wollte nur registrieren, dass Schienen 4.1 ActiveRecord akzeptiert Enums akzeptiert. Dokumentation: http://api.rubyonrails.org/v4.1.0/classes/ActiveRecord/Enum.html –

+0

danke !!! Ich bin sowieso nach Django gezogen :) –

Antwort

2

Fügen Sie den folgenden:

 
module ActiveRecord 
    module ConnectionAdapters #:nodoc: 
    class TableDefinition 
     def enum(*args) 
     options = args.extract_options! 
     column_names = args 

     column_names.each { |name| column(name, 'enum', options) } 
     end 
    end 
    end 
end 

lib/enum/table_definition.rb und es in Ihrem init.rb.

+0

schönes Stück Code, ich werde versuchen, es zu implementieren, Frage, das sieht einfach nett aus, also warum Schienen es nicht im Kern enthält? –

+0

Wahrscheinlich, weil nicht alle Datenbanken ENUMs unterstützen. – wesgarrison

4

Ich habe Dutzende dieser kleinen Enums, mit jeweils 3 bis 300 Einträge. Ich implementiere sie als Nachschlagetabellen. Ich habe keine Modelldatei für jeden; Ich benutze einige Metaprogrammierung, um ein Modell für jedes zu generieren, da jede Tabelle den gleichen Satz von Spalten (ID, Name, Beschreibung) hat.

Da einige Sets genug Elemente hatten, um ihre eigene Tabelle zu rechtfertigen, war es konsequenter, sie alle zu Tabellen zu verschieben. Nur eine weitere Option, wenn Sie später mehr von diesen Enums haben.

EDIT: Hier ist, wie ich die Modelle erzeugen:

ACTIVE_RECORD_ENUMS = %w{ 
    AccountState 
    ClientType 
    Country 
    # ... 
} 

ACTIVE_RECORD_ENUMS.each do |klass| 
    eval "class #{klass} < ActiveRecord::Base; end" 
    klass.constantize.class_eval do 
    class << self 

     def id_for(name) 
     ids[name.to_s.strip.humanize.downcase] 
     end 

     def value_for(id) 
     values[id.to_i] 
     end 

     def values 
     @values ||= find(:all).inject({}) {|h,m| h[m.send(primary_key)] = m.name; h} 
     end 

     def ids 
     @ids ||= self.values.inject({}) {|h, {k, v}| h[v.downcase] = k; h} 
     end 

    end 
    end 
end 

Diese Datei im Verzeichnis Modelle lebt und ist in application_config.rb enthalten. Das bin ich Sachen wie diese tun lässt:

AccountState.ids 
# => {"active" => 1, "deleted" => 2} 
AccountState.values 
# => {1 => "Active", 2 => "Deleted"} 
AccountState.id_for("Active") 
# => 1 
AccountState.value_for(1) 
# => "active" 
+0

Ich wäre sehr interessiert, den Code zu sehen oder mehr über die Metaprogrammierung, die Sie tun, um dies zu erreichen, wenn es nicht zu viel Mühe ist. –

+0

Bearbeitet, um Code hinzuzufügen. Ich habe es eine ganze Weile nicht mehr gesehen und musste feststellen, dass ich (wieder) nachschauen muss, was injiziert wird. Vielleicht ist das ein Argument für das Sammeln statt ... –

+0

Sehr geschickte Idee. Ich habe viele dieser Nachschlagetabellen, für die ich nie Modelldateien erstellen möchte. – wesgarrison

0

ok, lesen Sie einfach die ganze Schienen api und fand, was ich neeed und ich mag nicht :( Rails nicht emum als native Typ auf Migrationen unterstützen, here ist die info, ich brauche für ein Plugin oder eine andere Methode suchen

ich halte Sie auf dem Laufenden

+0

IIRC, Schienen unterstützt nur Funktionen, die von allen unterstützten Datenbanken implementiert werden, so dass es keine "out of the box" Enum-Unterstützung gibt. – MarkusQ

+0

FYI, weder Java Hibernate unterstützt dies ohne Erweiterung. – yclian

+0

großartig! jetzt muss ich nur wissen, wie man Hibernate auf ROR ausführt :) –

0

eine weitere Option:.. Drop SQL

def self.up 
    execute "ALTER TABLE `payments` ADD `status` ENUM('accepted', 'cancelled', 'pending')" 
end 
24

Blick auf Spitze # 3 auf http://zargony.com/2008/04/28/five-tips-for-developing-rails-applications

genau das, was Sie brauchen!

class User < ActiveRecord::Base 
    validates_inclusion_of :status, :in => [:active, :inactive] 

    def status 
    read_attribute(:status).to_sym 
    end 

    def status= (value) 
    write_attribute(:status, value.to_s) 
    end 
end 

HTH

+0

Dies löst jedoch das Problem, ist nur ein Workaround. Und keine Lösung für ein echtes Problem, das von OP gestellt wurde. Antwort von Adam Lassek ist relevanter. – Waseem

36

Sie können den Typ manuell angeben, indem Sie stattdessen die t.column Methode.Rails wird dies als eine String-Spalte interpretieren, und Sie können einfach ein Validator zum Modell wie Pavel hinzufügen vorgeschlagen:

class CreatePayments < ActiveRecord::Migration 
    def self.up 
    create_table :payments do |t| 
     t.string :concept 
     t.integer :user_id 
     t.text :notes 
     t.column :status, "ENUM('accepted', 'cancelled', 'pending')" 

     t.timestamps 
    end  
    end 

    def self.down 
    drop_table :payments 
    end 
end 

class Payment < ActiveRecord::Base 
    validates_inclusion_of :status, :in => %w(accepted cancelled pending) 
end 
+0

+1: es ist die einfachste Lösung – MickaelFM

+0

Was ist bei Verwendung von 'add_column'? –

+0

add_column: Tabellenname,: Spaltenname, "ENUM ('xx')" – agate

3

Auch die enumerated_attribute gem schafft Aufzählungen auf Objektebene.

enum_attr :status, %w(accepted cancelled ^pending) 

eine Zeichenfolge in der

Migration definieren
t.string :status 

Auch einige nette Features wie dynamische Prädikat Methoden zur Verfügung stellt.

http://github.com/jeffp/enumerated_attribute/tree/master

+0

was macht der ^? –

9

Sie können der (sehr) umfassende enumerated_attribute gem Jeffs versuchen OR mit dieser einfachen Abhilfe gehen:

class Person < ActiveRecord::Base 
    SEX = [:male, :female] 

    def sex 
    SEX[read_attribute(:sex)] 
    end 

    def sex=(value) 
    write_attribute(:sex, SEX.index(value)) 
    end 
end 

Und dann erklären das sex Attribut als Integer:

t.integer :sex 

Das hat sehr gut für mich funktioniert! = D

+0

können Sie erklären, wie das funktioniert? ist das Ändern einer Konstante oder? – Tallboy

+0

Es werden nur ganzzahlige Werte auf Symbole abgebildet. =) –

+1

Was passiert, wenn Sie ein neues Element in der Mitte der Liste hinzufügen? SEX = [: männlich,: fremd,: weiblich] wird alle existierenden Frauen in Aliens verwandeln, denn: alien hat jetzt einen Index von 1. – Jordan

0

Mit simple_form Ich benutze diese:

<%= f.input :gender, :collection => {'Male' => 'male','Female' => 'female'}, :include_blank => false %> 
Verwandte Themen