web-dev-qa-db-ja.com

Railsの主キーを文字列に変更する

つまり、StateとAcquisitionの2つのモデルがあります。州has_many買収。 51レコードの自動インクリメント整数主キーはかなりばかげているように感じました。そこで、StateのモデルをPKに変更しました(Stateは2文字の省略形です。実際の州名は、どこにも保存していません。

class State < ActiveRecord::Base  
  self.primary_key = "state"  
  has_many :acquisition_histories  
end

問題は、Acquisitionモデルを作成したときに、外部キー列state_idが整数として作成されたことです。より具体的には、スクリプト/生成された移行は次のことを行いました。

class CreateAcquisitions < ActiveRecord::Migration  
  def self.up  
    create_table :acquisitions do |t|  
      t.date :date  
      t.string :category  
      t.text :notes  
      t.references :state  
      t.timestamps  
    end
  end
end

T.referencesデータ型がintに設定していると仮定しています。問題は、Acquisitionクラスのcreateメソッドが、テーブルの取得のstate_idフィールドに状態の省略形を入れようとしていることです(移行スクリプトで:stateと表示されていても、データベースではstate_idと呼ばれます)。このメソッドは失敗しませんが、state_idフィールドに0を入力し、レコードはエーテルに入ります。

26
fr0man

しかし、私はこれが 価値があるよりも多くの問題 あなたが実際にしたい場合に備えて、他の場所でデフォルトに対して作業する余分な努力を考慮すると、そうなるかもしれないことに同意しますあなたが尋ねたことをしなさい:

状態の移行を作成します。

class CreateStatesTable < ActiveRecord::Migration  
  def change
    create_table :states, id: false do |t|
      t.string :state, limit: 2
      t.string :name
      t.index :state, unique: true
    end
  end
end

州モデル:

class State < ActiveRecord::Base
  self.primary_key = :state
end

Rails 3.2以前は、これはset_primary_key = :stateではなくself.primary_key=でした。参照: http://guides.rubyonrails.org/3_2_release_notes.html#active -record-deprecations

36
mkirk

ここにいる場合は...できるだけ早く離れて次の場所に移動してください: Railsを使用して、主キーを整数型の列にならないように設定するにはどうすればよいですか?

32
Wilhelm

私は主キーとしてUUIDを使用するプロジェクトに取り組んでいますが、正直なところ、絶対に必要であることが確実でない限り、UUIDはお勧めしません。文字列を主キーとして使用するデータベースでは変更せずに機能しないRailsプラグインがたくさんあります。

6
Bob Aman

Rails 5.1では、作成時に主キーのタイプを指定できます。

create_table :states, id: :string do |t|
# ...
end

から ドキュメント

シンボルを使用して、生成された主キー列のタイプを指定できます。

4
bloudermilk

mkirkの答え は偽の主キーを作成することに注意してください。これは、ActiveRecordに主キーが何であるかを通知する必要がある理由を説明しています。テーブルを調べると、

            Table "public.acquisitions"
 Column |         Type         | Modifiers
--------+----------------------+-----------
 state  | character varying(2) |
 name   | character varying    |
Indexes:
    "index_acquisitions_on_state" UNIQUE, btree (state)

実際には、これは期待どおりに機能するので、問題はありませんが、もっと良いかもしれません。


id列を保持し、そのタイプをstring *に変更できます。移行は次のようになります

class CreateAcquisitionsTable < ActiveRecord::Migration  
  def change
    create_table :acquisitions do |t|
      t.string :name
    end
    change_column :acquisitions, :id, :string, limit: 2
  end
end

テーブルを調べると、null制約ではなく、一意キー制約(一意のインデックスは不要)、自動インクリメントキーなど、すべての機能を備えた実際の主キーがあることがわかります。

                                Table "public.acquisitions"
 Column |         Type         |                     Modifiers
--------+----------------------+---------------------------------------------------
 id     | character varying(2) | not null default nextval('acquisitions_id_seq'::regclass)
 name   | character varying    |
Indexes:
    "acquisitions_pkey" PRIMARY KEY, btree (id)

そしてプライマリが何であるかをActiveRecordに明示的に伝える必要はありません。

何も指定されていない場合は、デフォルトIDの設定を検討することをお勧めします。

class MyModel < ActiveRecord::Base
  before_create do
    self.id = SecureRandom.uuid unless self.id
  end
end

*免責事項:正当な理由がない限り、デフォルトの主キーを変更しないでください。

3
Dennis

Railsの規則に従う必要があります。追加の主キーは、まったく問題ではありません。使用するだけです。

2
August Lilleaas
class CreateAcquisitions < ActiveRecord::Migration  
    def self.up  
        create_table :acquisitions, :id => false do |t|  
          t.date :date  
          t.string :category  
          t.text :notes  
          t.references :state  
          t.timestamps
        end
    end
end
1
todd

私は主キーとして使用される文字列を少し経験しましたが、それは***の苦痛です。デフォルトでは、デフォルトの:controller /:action /:idパターンでオブジェクトを渡したい場合、:idは文字列になり、一部のIDが奇妙な形式になると、ルーティングの問題が発生する可能性があることに注意してください;)

1