web-dev-qa-db-fra.com

Comment utiliser l'identifiant long dans les applications Rails?

Comment puis-je changer le type (par défaut) des identifiants d'ActiveRecord? int n'est pas assez long, je préférerais longtemps. J'ai été surpris qu'il n'y ait pas de: long pour les migrations - est-ce qu'on utilise juste une décimale?

38
Björn

Crédits à http://moeffju.net/blog/using-bigint-columns-in-Rails-migrations

class CreateDemo < ActiveRecord::Migration
  def self.up
    create_table :demo, :id => false do |t|
      t.integer :id, :limit => 8
    end
  end
end
  • Voir l'option :id => false qui désactive la création automatique du champ id
  • La ligne t.integer :id, :limit => 8 produira un champ entier de 64 bits
49
Notinlist

Pour définir le type de colonne de clé primaire par défaut , les fichiers de migration ne sont pas l'endroit pour déconner.

Au lieu de cela, collez ceci au bas de votre config/environment.rb

ActiveRecord::ConnectionAdapters::MysqlAdapter::NATIVE_DATABASE_TYPES[:primary_key] = "BIGINT UNSIGNED DEFAULT NULL auto_increment PRIMARY KEY"

Et toutes vos tables doivent être créées avec le type de colonne prévu pour id:

+--------------+---------------------+------+-----+---------+----------------+
| Field        | Type                | Null | Key | Default | Extra          |
+--------------+---------------------+------+-----+---------+----------------+
| id           | bigint(20) unsigned | NO   | PRI | NULL    | auto_increment | 

Une fois que vous avez accompli ce que vous aviez prévu de faire, la question suivante est probablement: "Comment puis-je utiliser le même type de colonne pour les colonnes de clé étrangère?" comme il n’a pas de sens d’avoir la clé primaire people.id comme bigint(20) unsigned, et person_id être int(11) ou quoi que ce soit d'autre?

Pour ces colonnes, vous pouvez vous référer aux autres suggestions, par exemple.

t.column :author_id, 'BIGINT UNSIGNED'
t.integer :author_id, :limit => 8

UPDATE: @Notinlist, pour utiliser une colonne arbitraire pour la clé primaire sur des tables arbitraires, vous devez effectuer la danse create_table-change_column:

create_table(:users) do |t|
  # column definitions here..
end
change_column :users, :id, :float # or some other column type

par exemple. si je voulais guid au lieu d'entiers auto-incrémentés,

create_table(:users, :primary_key => 'guid') do |t|
  # column definitions here..
end
change_column :users, :guid, :string, :limit => 36
43
choonkeat

Cela est difficile à définir pour la clé primaire avec les migrations car Rails la met automatiquement. 

Vous pouvez changer n'importe quelle colonne plus tard comme ceci:

change_column :foobars, :something_id, 'bigint'

Vous pouvez spécifier des ID non principaux en tant que types personnalisés dans votre migration initiale, comme suit:

create_table :tweets do |t|
  t.column :Twitter_id, 'bigint'
  t.column :Twitter_in_reply_to_status_id, 'bigint'
end

Là où j'ai "bigint", vous pouvez mettre n'importe quel texte que votre base de données utiliserait pour le type de colonne de base de données que vous souhaitez utiliser (par exemple, "unsigned long").

Si vous avez besoin que votre colonne id soit bigint, le moyen le plus simple consiste à créer la table, puis à modifier la colonne dans la même migration avec change_column. 

Avec PostgreSQL et SQLite, les modifications de schéma sont atomiques, ce qui ne laissera pas votre base de données dans un état étrange si la migration échoue. Avec MySQL, vous devez être plus prudent.

7
Luke Francl

Selon la documentation de l'API Rails, les options possibles pour le type sont les suivantes:

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

Vous pouvez utiliser: décimal, ou vous pouvez exécuter une commande directement si vous devez:

class MyMigration
  def self.up
    execute "ALTER TABLE my_table ADD id LONG"
  end
end

Comme l'a souligné wappos, vous pouvez utiliser des options auxiliaires telles que: limit pour indiquer à ActiveRecord la taille souhaitée de la colonne. Donc, vous utiliseriez la colonne: int avec une plus grande: limite.

6
Yehuda Katz

Si quelqu'un a besoin de cela avec PostgreSQL, créez un initialiseur comme ceci:

# config/initializers/bigint_primary_keys.rb
ActiveRecord::Base.establish_connection
ActiveRecord::ConnectionAdapters::PostgreSQLAdapter::NATIVE_DATABASE_TYPES[:primary_key] = 'bigserial primary key'

En raison du chargement paresseux dans Rails 3.2 (et peut-être même dans des versions antérieures), ActiveRecord::ConnectionAdapters::PostgreSQLAdapter ne sera pas nécessaire jusqu'à ce que vous établissiez la connexion à la base de données.

5
Brandan

Dans Rails4, vous pouvez le faire.

Voici un exemple pour créer un modèle Dummy dans Rails4 & postgres,

xxx_migrate_dummies.rb:

class CreateDummies < ActiveRecord::Migration
  def change
    create_table :dummies, :id => false do |t|
      t.column :id, :serial8, primary_key: true
      t.string :name, :limit => 50, null: false
      t.integer :size, null: false

      t.column :create_date, :timestamptz, null: false
    end
  end
end

Ce qu'il a fait:

  • Il utilise serial8 comme type d'identifiant, qui est un entier de 64 bits, et le définit comme primary key.
  • Il utilise timestamptz comme type date/heure, qui contient les informations de fuseau horaire, ce qui est important pour une application qui utilise plusieurs fuseaux horaires.
4
Eric Wang

Rails 3, MySQL:

t.column :foobar, :int, :limit => 8

Ne me donne pas un bigint, seulement un int. cependant,

t.column :Twitter_id, 'bigint'

fonctionne bien. (Bien que cela me lie à MySQL.)

2
Duke

J'ai écrit une perle appelée activerecord-native_db_types_override qui vous permet de modifier les types de données qui seront utilisés dans vos migrations.

Dans votre Gemfile, ajoutez:

gem 'activerecord-native_db_types_override'

puis dans config/environment.rb, pour utiliser des identifiants longs dans postgres, ajoutez:

NativeDbTypesOverride.configure({
  postgres: {
    primary_key: { name: "bigserial primary key"}
  }
})

Voir son README pour des informations à jour.

0
Gary S. Weaver

Vous pouvez le faire comme ça:

class CreateUsers < ActiveRecord::Migration[5.0]
  def change
    create_table :users, id: :bigserial do |t|
      t.string :name
    end
  end
end
0
Alexander Gorg