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.

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

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 .


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

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

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} 

3

Rails 5+ (funktioniert auch mit virtuellen Attributen):

Model.attribute_types['some_attribute'].type

Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.