2010-03-08 21 views
55

Me gustaría saber si es posible obtener los tipos (como los conoce AR, por ejemplo, en el script de migración y la base de datos) programáticamente (sé que los datos existen allí en algún lugar) .Obteniendo los tipos de los atributos en un objeto ActiveRecord

Por ejemplo, puedo tratar con todos los nombres de los atributos:

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

.attributes simplemente devuelve un mapeo de los nombres de sus valores actuales (por ejemplo, no hay información de tipo si el campo no está establecido).

Algunos de los lugares que he visto con la información del tipo:

en escritura/consola, escriba el nombre de una entidad AR:

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

Así que está claro que conoce los tipos. Además, existe .column_for_attribute, que toma un nombre de attr y devuelve un objeto de columna, que tiene el tipo enterrado en el objeto de columna de base de datos subyacente, pero no parece ser una forma limpia de obtenerlo.

También me interesaría si hay una forma que sea amigable para el nuevo "ActiveModel" que viene (rails3) y está desacoplada de las especificaciones de la base de datos (pero tal vez la información tipográfica no formará parte de ella, puedo Parece que no sé si lo es).

Gracias.

Respuesta

84

En Rails 3, para su modelo "Driver", quiere Driver.columns_hash.

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

Si desea iterar a través de ellos, que haría algo como esto:

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

que tendrá salida el siguiente:

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

¿Sabes cómo puedo probar si un valor coincide con una columna, algo como esto '2.is_a? Driver.columns_hash ["nombre"]. Tipo ' – mariowise

+0

No, no sé. –

+0

Puedo confirmar que esto todavía funciona en Rails 4.2 – Phil

19

Puede acceder a los tipos de las columnas al hacer esto:

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

Si desea obtener una lista de todos los tipos de columna en un modelo en particular, se puede hacer:

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

Gracias. Supongo que esto no formará parte de ActiveModel, ya que está vinculado a columnas (que probablemente no llegarán a AM). Pero eso funciona simplemente increíble para AR. Sabes que realmente lo sabía en el fondo de mi mente, pero por alguna razón lo bloqueé. –

7

En los carriles 5, es posible hacer esto independientemente de la base de datos. Eso es importante si usa la nueva API de atributos para definir atributos (adicionales).

Obtener todos los atributos de una clase del modelo:

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

Obtención del tipo:

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

Eso es a veces más información de la necesaria. Hay una función de conveniencia que mapea todos estos tipos a un conjunto básico (: número entero,: Cadena etc.)

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

También puede obtener todos los datos en una llamada con attribute_types que devuelve un hash 'name': type.

+3

Esto también funciona en Rails 4.2. Es importante tener en cuenta que 'type_for_attribute ('id')' solo toma una cadena. Es un poco confuso porque 'type_for_attribute ('id'). Type' devuelve un símbolo. –

+0

Si por independencia de la base de datos se refiere al ORM, entonces Mongoid aún no ha implementado este 'type_for_attribute'. Tal vez después de que Rails 5 tenga un lanzamiento oficial. –

1

Este fragmento le dará todos los atributos de un modelo con los tipos de datos de base de datos asociados en un hash. Simplemente reemplace Post con su Modelo de registro activo.

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

Se devolverá un hash como este.

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

En los carriles 5 que esto le dará una lista de todos los nombres de campo junto con su tipo de datos:

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

Nota 'type_for_attribute' espera cadenas. ¡Felizmente toma símbolos, o nombres inexistentes, devolviendo un ActiveModel :: Type :: Value que no se convierte! OMI un error, intentaré informar/corregir. –

Cuestiones relacionadas