web-dev-qa-db-fra.com

Existe-t-il une documentation pour les types de colonne Rails?

Je cherche plus que la simple liste de types qui se trouve sur cette page :

: primary_key,: string,: text,: integer,: float,: decimal,: datetime,: timestamp,: time,: date,: binary,: boolean

Mais existe-t-il une documentation qui définit ces champs?

Plus précisément:

  • Quelle est la différence entre :string et :text?
  • Entre :float et :decimal?
  • Quelles sont les caractéristiques distinctives de :time, :timestamp et :datetime?

Les nuances de ces types sont-elles documentées quelque part?

EDIT: Les points d'implémentations de la plate-forme DB ne sont pas pertinents pour la question que j'essaie de poser. Si, par exemple, :datetime n'a pas une signification voulue dans la documentation Rails, à quoi sert db-adapter-writerers lors du choix du type de colonne correspondant?

177
Grant Birchmeier

Lignes directrices construites à partir de l'expérience personnelle:

  • Chaîne :
    • Limité à 255 caractères (selon le SGBD)
    • Utiliser pour les champs de texte courts (noms, emails, etc.)
  • Texte :
    • Longueur illimitée (selon le SGBD)
    • Utiliser pour les commentaires, les articles de blog, etc. Règle générale: si elle est capturée via textarea, utilisez Text. Pour une entrée utilisant des champs de texte, utilisez string.
  • Entier :
    • Des nombres entiers
  • Flottant :
    • Nombres décimaux stockés avec une précision en virgule flottante
    • La précision est fixe, ce qui peut poser problème pour certains calculs. généralement pas bon pour les opérations mathématiques en raison d'arrondis inexacts.
  • Décimal :
    • Les nombres décimaux stockés avec une précision qui varie en fonction des besoins de vos calculs; utilisez-les pour les mathématiques qui doivent être précises
    • Voir this post pour des exemples et une explication détaillée des différences entre les flottants et les décimales.
  • Booléen :
    • Utilisez pour stocker les attributs true/false (c'est-à-dire les choses qui n'ont que deux états, comme on/off)
  • Binaire :
    • Utilisé pour stocker des images, des films et d'autres fichiers dans leur format brut d'origine sous forme de morceaux de données appelés blobs
  • : primary_key
    • Ce type de données est un espace réservé que Rails convertit en le type de données de clé primaire requis par la base de données de votre choix (c'est-à-dire serial primary key dans PostgreSQL). Son utilisation est quelque peu compliquée et non recommandée.
    • Utilisez des contraintes de modèle et de migration (telles que validates_uniqueness_of et add_index avec l'option :unique => true) à la place pour simuler la fonctionnalité de clé primaire sur l'un de vos propres champs.
  • Date :
    • Ne stocke qu'une date (année, mois, jour)
  • Heure :
    • Ne stocke qu'une heure (heures, minutes, secondes)
  • DateTime :
    • Stocke la date et l'heure
  • Horodatage
    • Stocke la date et l'heure
    • Remarque: pour Rails, Timestamp et DateTime signifient la même chose (utilisez l'un ou l'autre type pour stocker la date et l'heure). Pour la description de TL et DR expliquant pourquoi les deux existent, lisez le paragraphe du bas.

Ce sont les types sur lesquels la confusion existe souvent; J'espère que ça aide. Je ne sais vraiment pas pourquoi il n'y a pas de documentation officielle à ce sujet. De plus, j'imagine que les adaptateurs de base de données que vous avez mentionnés ont été écrits par les mêmes auteurs de Rails. Ils n'ont donc probablement pas besoin de documentation avant de les écrire. J'espère que cela t'aides!

Remarque: la présence de :DateTime et de :Timestamp, d'après ce que je peux trouver, est incluse dans Rails principalement pour des raisons de compatibilité avec les systèmes de base de données. Par exemple, le type de données TIMESTAMP de MySQL est stocké sous la forme d'un horodatage Unix. Sa plage valide va de 1970 à 2038 et le temps est stocké sous forme de nombre de secondes écoulées depuis le dernier Epoch , ce qui est supposé être standard, mais peut en pratique différer d'un système à l'autre. Reconnaissant que le temps relatif n’était pas une bonne chose à avoir dans les bases de données, MySQL a plus tard introduit le type de données DATETIME, qui stocke chaque chiffre de l’année, du mois, du jour, de l’heure, des minutes et des secondes, au prix d’une augmentation de taille. . Le type de données TIMESTAMP a été conservé pour des raisons de compatibilité ascendante. D'autres systèmes de bases de données ont connu des évolutions similaires. Rails a reconnu l'existence de plusieurs normes et a fourni des interfaces aux deux. Cependant, Rails ActiveRecord utilise par défaut les dates :Timestamp et :DateTime vers les dates UTC stockées dans DATETIME de MySql, de sorte que les programmeurs Rails ne font aucune différence fonctionnelle. . Celles-ci existent pour que les utilisateurs qui souhaitent différencier les deux puissent le faire. (Pour une explication plus détaillée, voir this SO answer).

391
aguazales

De Rails code de la source de branche principale que j'ai trouvé:

mysql_adapter abstrait

#activerecord/lib/active_record/connection_adapters/abstract_mysql_adapter.rb

  NATIVE_DATABASE_TYPES = {
    primary_key: "bigint auto_increment PRIMARY KEY",
    string:      { name: "varchar", limit: 255 },
    text:        { name: "text", limit: 65535 },
    integer:     { name: "int", limit: 4 },
    float:       { name: "float" },
    decimal:     { name: "decimal" },
    datetime:    { name: "datetime" },
    timestamp:   { name: "timestamp" },
    time:        { name: "time" },
    date:        { name: "date" },
    binary:      { name: "blob", limit: 65535 },
    boolean:     { name: "tinyint", limit: 1 },
    json:        { name: "json" },
  }

  # Maps logical Rails types to MySQL-specific data types.
  def type_to_sql(type, limit = nil, precision = nil, scale = nil, unsigned = nil)
    sql = case type.to_s
    when 'integer'
      integer_to_sql(limit)
    when 'text'
      text_to_sql(limit)
    when 'blob'
      binary_to_sql(limit)
    when 'binary'
      if (0..0xfff) === limit
        "varbinary(#{limit})"
      else
        binary_to_sql(limit)
      end
    else
      super(type, limit, precision, scale)
    end

    sql << ' unsigned' if unsigned && type != :primary_key
    sql
  end    

# and integer ...

  def integer_to_sql(limit) # :nodoc:
    case limit
    when 1; 'tinyint'
    when 2; 'smallint'
    when 3; 'mediumint'
    when nil, 4; 'int'
    when 5..8; 'bigint'
    else raise(ActiveRecordError, "No integer type has byte size #{limit}")
    end
  end

 # and text ..

  def text_to_sql(limit) # :nodoc:
    case limit
    when 0..0xff;               'tinytext'
    when nil, 0x100..0xffff;    'text'
    when 0x10000..0xffffff;     'mediumtext'
    when 0x1000000..0xffffffff; 'longtext'
    else raise(ActiveRecordError, "No text type has byte length #{limit}")
    end
  end

# and binary ...

    def binary_to_sql(limit) # :nodoc:
      case limit
      when 0..0xff;               "tinyblob"
      when nil, 0x100..0xffff;    "blob"
      when 0x10000..0xffffff;     "mediumblob"
      when 0x1000000..0xffffffff; "longblob"
      else raise(ActiveRecordError, "No binary type has byte length #{limit}")
      end
    end

la méthode super dans type_to_sql

#activerecord/lib/active_record/connection_adapters/abstract/schema_statements.rb
  def type_to_sql(type, limit = nil, precision = nil, scale = nil) #:nodoc:
    type = type.to_sym if type
    if native = native_database_types[type]
      column_type_sql = (native.is_a?(Hash) ? native[:name] : native).dup

      if type == :decimal # ignore limit, use precision and scale
        scale ||= native[:scale]

        if precision ||= native[:precision]
          if scale
            column_type_sql << "(#{precision},#{scale})"
          else
            column_type_sql << "(#{precision})"
          end
        elsif scale
          raise ArgumentError, "Error adding decimal column: precision cannot be empty if scale is specified"
        end

      elsif [:datetime, :time].include?(type) && precision ||= native[:precision]
        if (0..6) === precision
          column_type_sql << "(#{precision})"
        else
          raise(ActiveRecordError, "No #{native[:name]} type has precision of #{precision}. The allowed range of precision is from 0 to 6")
        end
      elsif (type != :primary_key) && (limit ||= native.is_a?(Hash) && native[:limit])
        column_type_sql << "(#{limit})"
      end

      column_type_sql
    else
      type.to_s
    end
  end
9
fangxing