2010-03-08 8 views
55

Ich möchte wissen, ob es möglich ist, die Typen (wie von AR bekannt - zB in dem Migrationsskript und der Datenbank) programmgesteuert zu erhalten (ich weiß, dass die Daten dort irgendwo vorhanden sind) .Abrufen der Typen der Attribute in einem ActiveRecord-Objekt

Zum Beispiel kann ich mit allen Attributnamen umgehen:

ar.attribute_names.each { |name| puts name } 

.attributes gibt nur eine Zuordnung der Namen auf ihre aktuellen Werte (zB keine Typinformationen, wenn das Feld nicht gesetzt ist).

Einige Orte, die ich mit der Typinformation gesehen haben:

in Skript/Konsole, den Namen eines AR Entitätstyp:

>> Driver 
=> Driver(id: integer, name: string, created_at: datetime, updated_at: datetime) 

So klar es die Typen kennt. Außerdem gibt es .column_for_attribute, das einen attr-Namen annimmt und ein column-Objekt zurückgibt, dessen Typ im zugrunde liegenden Datenbankspaltenobjekt vergraben ist, aber es scheint kein sauberer Weg zu sein, um es zu erhalten.

würde mich auch interessieren, wenn es einen Weg gibt, der für das neue "ActiveModel", das kommt (rails3), freundlich ist und von Datenbankspezifikationen entkoppelt ist (aber vielleicht Typ Info nicht dazu gehört, kann ich Es scheint nicht herauszufinden, ob es so ist.

Danke.

Antwort

84

In Rails 3 möchten Sie für Ihr Modell "Driver" Driver.columns_hash.

Driver.columns_hash["name"].type #returns :string 

Wenn Sie durch den Freunden zu wollen, würden Sie so etwas tun:

Driver.columns_hash.each {|k,v| puts "#{k} => #{v.type}"} 

, die der Ausgang folgende:

id => integer 
name => string 
created_at => datetime 
updated_at => datetime 
+0

Wissen Sie, wie kann ich testen, ob ein Wert mit einer Spalte übereinstimmt, etwa '2.is_a? Driver.columns_hash ["name"]. Type ' – mariowise

+0

Nein, weiß nicht. –

+0

Ich kann bestätigen, dies funktioniert immer noch in Rails 4.2 – Phil

19

Sie die Typen der Spalten, indem Sie diese zugreifen können:

#script/console 
Driver.columns.each {|c| puts c.type} 

Wenn Sie eine Liste aller Spaltentypen in einem bestimmten Modell bekommen möchten, können Sie tun:

Driver.columns.map(&:type) #gets them all 
Driver.columns.map(&:type).uniq #gets the unique ones 
+0

Danke. Ich vermute, dass dies nicht Teil von ActiveModel sein wird, da es an Spalten gebunden ist (was es wahrscheinlich nicht zu AM macht). Aber das funktioniert einfach großartig für AR. Du weißt, dass ich das im Hinterkopf wusste, aber aus irgendeinem Grund blockierte. –

7

In Rails 5 können Sie tun dies unabhängig von der Datenbank. Das ist wichtig, wenn Sie die neue Attribute-API verwenden, um (zusätzliche) Attribute zu definieren.

alle Attribute aus einer Modellklasse Ersten:

pry> User.attribute_names 
=> ["id", 
"firstname", 
"lastname", 
"created_at", 
"updated_at", 
"email",... 

gibt es die Art:

pry> User.type_for_attribute('email') 
=> #<ActiveRecord::ConnectionAdapters::AbstractMysqlAdapter::MysqlString:0x007ffbab107698 
@limit=255, 
@precision=nil, 
@scale=nil> 

, die manchmal mehr Informationen sind als nötig. Es gibt eine Komfortfunktion, die diese Typen alle Karten bis auf einen Kernsatz (: integer,: string usw.)

> User.type_for_attribute('email').type 
=> :string 

Sie auch alle diese Daten in einem Aufruf mit attribute_types bekommen kann, die einen 'name': type Hash zurückgibt.

+3

Dies funktioniert auch in Rails 4.2. Es ist wichtig zu beachten, dass 'type_for_attribute ('id')' nur eine Zeichenfolge benötigt. Es ist ein wenig verwirrend, weil 'type_for_attribute ('id'). Type 'ein Symbol zurückgibt. –

+0

Wenn durch Datenbankunabhängig das ORM gemeint ist, dann hat Mongoid dieses 'type_for_attribute' noch nicht implementiert. Vielleicht nach Rails 5 hat eine offizielle Veröffentlichung. –

1

Dieses Snippet enthält alle Attribute eines Modells mit den zugeordneten Datenbankdatentypen in einem Hash. Ersetzen Sie Post einfach durch Ihr Active Record-Modell.

Post.attribute_names.map {|n| [n.to_sym,Post.type_for_attribute(n).type]}.to_h 

Gibt einen Hash wie folgt zurück.

=> {:id=>:integer, :title=>:string, :body=>:text, :created_at=>:datetime, :updated_at=>:datetime, :topic_id=>:integer, :user_id=>:integer} 
3

In Schienen 5 dies wird Ihnen eine Liste aller Feldnamen zusammen mit ihren Datentyp:

Model_Name.attribute_names.each do |k| puts "#{k} = #{Model_Name.type_for_attribute(k).type}" end 
+0

Hinweis 'type_for_attribute 'erwartet Strings. Es nimmt glücklich Symbole oder nicht existente Namen und gibt einen ActiveModel :: Type :: Value zurück, der kein Casting durchführt! IMO ein Fehler, ich werde versuchen, zu melden/zu beheben. –