Czy istnieje dokumentacja dla typów kolumn Rails?

181

Szukam więcej niż prostego wpisu typu, który można znaleźć na tej stronie :

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

Ale czy jest jakaś dokumentacja, która faktycznie definiuje te pola?

Konkretnie:

  • Jaka jest różnica między :stringi :text?
  • Pomiędzy :floata :decimal?
  • Jakie są cechy wyróżniające :time, :timestampi :datetime?

Czy niuanse tego typu są gdziekolwiek udokumentowane?

EDYCJA: Punkty implementacji platformy DB nie mają znaczenia dla pytania, które próbuję zadać. Jeśli, powiedzmy, :datetimenie ma zdefiniowanego zamierzonego znaczenia w dokumentacji Railsów, to po co piszą db-adapter-writer przy wyborze odpowiedniego typu kolumny?

Grant Birchmeier
źródło
1
Jakie są tego typu, przepraszam za mój wybór słów, rzeczy , tak zwanych? Czy to są pola, atrybuty czy co. Szukałem innych rzeczach innych niż :stringi :textnie mogłem znaleźć innego niż to. Zastanawiałem się więc, czy nie w przyszłości.
l1zZY
2
@ l1zZY, ​​termin, którego możesz szukać, to „typy danych”.
thatpaintingelephant

Odpowiedzi:

397

Wytyczne zbudowane na podstawie osobistego doświadczenia:

  • Ciąg :
    • Ograniczony do 255 znaków (w zależności od DBMS)
    • Użyj do krótkich pól tekstowych (imiona, e-maile itp.)
  • Tekst :
    • Nieograniczona długość (w zależności od DBMS)
    • Używaj do komentarzy, postów na blogu itp. Ogólna ogólna zasada: jeśli jest przechwytywany przez textarea, użyj Text. Do wprowadzania danych za pomocą pól tekstowych użyj ciągu znaków.
  • Liczba całkowita :
    • Wszystkie liczby
  • Pływak :
    • Liczby dziesiętne przechowywane z precyzją zmiennoprzecinkową
    • Precyzja jest ustalona, ​​co może być problematyczne w przypadku niektórych obliczeń; ogólnie nie nadaje się do operacji matematycznych z powodu niedokładnego zaokrąglania.
  • Dziesiętny :
    • Liczby dziesiętne przechowywane z precyzją, która zmienia się w zależności od potrzeb obliczeniowych; używaj ich do matematyki, która musi być dokładna
    • Zobacz ten post dla przykładów i dogłębnego wyjaśnienia różnic między zmiennoprzecinkowymi i dziesiętnymi.
  • Boolean :
    • Służy do przechowywania atrybutów prawda / fałsz (tj. Rzeczy, które mają tylko dwa stany, np. Włącz / wyłącz)
  • Binarny :
    • Służy do przechowywania obrazów, filmów i innych plików w ich oryginalnym, surowym formacie w kawałkach danych zwanych obiektami BLOB
  • :klucz podstawowy
    • Ten typ danych jest symbolem zastępczym, który Railsy tłumaczy na dowolny typ danych klucza podstawowego wymagany przez twoją bazę danych (np. serial primary keyW postgreSQL). Jego użycie jest nieco skomplikowane i nie jest zalecane.
    • Zamiast tego używaj ograniczeń modelu i migracji (takich jak validates_uniqueness_ofi add_indexz :unique => trueopcją), aby symulować funkcjonalność klucza podstawowego w jednym z twoich własnych pól.
  • Data :
    • Przechowuje tylko datę (rok, miesiąc, dzień)
  • Czas :
    • Przechowuje tylko czas (godziny, minuty, sekundy)
  • Data i godzina :
    • Przechowuje datę i godzinę
  • Znak czasu
    • Przechowuje datę i godzinę
    • Uwaga: Na potrzeby Railsów zarówno datownik, jak i data oznaczają to samo (użyj obu typów, aby zapisać datę i godzinę). Aby zapoznać się z opisem przyczyn istnienia obu TL, DR, przeczytaj dolny akapit.

Są to typy, w których często istnieje zamieszanie; Mam nadzieję, że to pomoże. Naprawdę nie wiem, dlaczego nie ma oficjalnej dokumentacji na ich temat. Wyobrażam sobie również, że wspomniane przez ciebie adaptery baz danych zostały napisane przez te same osoby, które napisały Railsy, ​​więc prawdopodobnie nie potrzebowały żadnej dokumentacji, kiedy pisały adaptery. Mam nadzieję że to pomoże!

Uwaga: obecność obu :DateTimei :Timestamp, z tego, co mogę znaleźć, jest uwzględniona przez Rails głównie ze względu na kompatybilność z systemami baz danych. Na przykład TIMESTAMPtyp danych MySQL jest przechowywany jako uniksowy znacznik czasu. Jego prawidłowy zakres wynosi od 1970 do 2038 roku, a czas jest przechowywany jako liczba sekund, które upłynęły od ostatniej epoki , co jest podobno standardowe, ale w praktyce może różnić się w zależności od systemu. Uznając, że względny czas nie był dobry w bazach danych, MySQL wprowadził później DATETIMEtyp danych, który przechowuje każdą cyfrę w roku, miesiącu, dniu, godzinie, minucie i sekundzie, kosztem zwiększenia rozmiaru. TheTIMESTAMPtyp danych został zachowany dla kompatybilności wstecznej. Inne systemy baz danych przeszły podobne zmiany. Railsy uznały istnienie wielu standardów i zapewniły interfejsy do obu. Jednak Rails ActiveRecord domyślnie ustawia zarówno daty, jak :Timestampi :DateTimedaty UTC przechowywane w MySql DATETIME, więc nie ma to żadnej różnicy funkcjonalnej dla programistów Rails. Istnieją one po to, aby użytkownicy, którzy chcą rozróżnić między nimi, mogą to zrobić. (Aby uzyskać bardziej szczegółowe wyjaśnienie, zobacz odpowiedź SO).

aguazales
źródło
21
To niesamowity napis @aguazales. Wydaje się, że to przeoczenie, że dokumentacja Railsów nie ma czegoś takiego.
Grant Birchmeier,
Dzięki :) I całkowicie się zgadzam, ActiveRecord i jego typy danych są tak ważne dla Railsów, idk, dlaczego to nie jest standardowa dokumentacja.
aguazales
2
Długość tekstu nie zawsze jest nieograniczona - w MySQL jest on ograniczony do około 16 KB. Istnieją typy baz danych MEDIUMTEXT i LONGTEXT, jeśli potrzebujesz więcej niż 16 KB.
Haegin
3
Jest to również dobre źródło Typy danych migracji Railsów - MySql - Postgresql - SQLite . Wiem, że jest to specyficzne dla bazy danych, ale znajomość faktycznej implementacji jest nadal pomocna w zrozumieniu typów baz danych w szynach.
Nate
1
Nie mogę być w 100% pewien, ale myślę, że zasób Nate'a został tutaj przeniesiony .
aguazales
10

Z kodu źródłowego gałęzi Rails master znalazłem:

streszczenie mysql_adapter

#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

superw type_to_sqlmetodzie

#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
Fangxing
źródło