Abrufen von Attributtypen in einem ActiveRecord-Objekt

70

Ich würde gerne wissen, ob es möglich ist, die Typen (wie von AR bekannt - z. B. im Migrationsskript und in der Datenbank) programmgesteuert abzurufen (ich weiß, dass die Daten dort irgendwo vorhanden sind).

Zum Beispiel kann ich mit allen Attributnamen umgehen:

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

.attributes gibt nur eine Zuordnung der Namen zu ihren aktuellen Werten zurück (z. B. keine Typinformationen, wenn das Feld nicht festgelegt ist).

Einige Orte, an denen ich es mit den Typinformationen gesehen habe:

Geben Sie in Skript / Konsole den Namen einer AR-Entität ein:

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

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

Mich würde auch interessieren, ob es einen Weg gibt, der für das kommende neue "ActiveModel" (Rails3) geeignet und von den Datenbankspezifikationen entkoppelt ist (aber vielleicht sind Typinformationen nicht Teil davon, ich kann es nicht scheinen herausfinden, ob es ist).

Vielen Dank.

Michael Neale
quelle

Antworten:

106

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

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

Wenn Sie sie durchlaufen möchten, gehen Sie wie folgt vor:

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

welches folgendes ausgibt:

id => integer
name => string
created_at => datetime
updated_at => datetime
Grant Birchmeier
quelle
Wissen Sie, wie ich testen kann, ob ein Wert mit einer Spalte übereinstimmt, so etwas2.is_a? Driver.columns_hash["name"].type
Mariowise
Dies funktioniert nicht mit virtuellen Attributen in Schienen 5+
estani
27

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

Abrufen aller Attribute aus einer Modellklasse:

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

Den Typ bekommen:

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

Das sind manchmal mehr Informationen als nötig. Es gibt eine praktische Funktion, die alle diese Typen einem Kernsatz zuordnet (: Ganzzahl ,: Zeichenfolge usw.).

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

Sie können all diese Daten auch in einem Aufruf mit attribute_types abrufen, der einen 'name': typeHash zurückgibt .

Matthias Winkelmann
quelle
3
Dies funktioniert auch in Rails 4.2. Es ist wichtig zu beachten, dass type_for_attribute('id')nur eine Zeichenfolge benötigt wird. Es ist etwas verwirrend, weil type_for_attribute('id').typeein Symbol zurückgegeben wird.
Xander-Miller
1
Wenn Sie mit datenbankunabhängig ORM gemeint haben, hat Mongoid dies type_for_attributenoch nicht implementiert . Vielleicht nachdem Rails 5 eine offizielle Veröffentlichung hat.
Cyril Duchon-Doris
22

Sie können auf die Arten der Spalten zugreifen, indem Sie Folgendes tun:

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

Wenn Sie eine Liste aller Spaltentypen in einem bestimmten Modell erhalten möchten, haben Sie folgende Möglichkeiten:

Driver.columns.map(&:type) #gets them all
Driver.columns.map(&:type).uniq #gets the unique ones
Mike Trpcic
quelle
Vielen Dank. Ich vermute, dass dies nicht Teil von ActiveModel sein wird, da es an Spalten gebunden ist (was es wahrscheinlich nicht zu AM schafft). Aber das funktioniert einfach großartig für AR. Du weißt, ich wusste das tatsächlich im Hinterkopf, aber aus irgendeinem Grund hat es es blockiert.
Michael Neale
7

In Schienen 5 erhalten Sie eine Liste aller Feldnamen mit ihrem Datentyp:

Model_Name.attribute_names.each do |k| puts "#{k} = #{Model_Name.type_for_attribute(k).type}" end
Amin
quelle
Hinweis type_for_attributeerwartet Zeichenfolgen. Es werden gerne Symbole oder nicht vorhandene Namen verwendet, um einen ActiveModel :: Type :: -Wert zurückzugeben, der kein Casting ausführt! IMO ein Fehler, ich werde versuchen, zu melden / zu beheben.
Beni Cherniavsky-Paskin
3

Dieses Snippet gibt Ihnen alle Attribute eines Modells mit den zugehörigen 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 diesen zurück.

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

Rails 5+ (funktioniert auch mit virtuellen Attributen):

Model.attribute_types['some_attribute'].type
estani
quelle