Rails를 사용하여 어떻게 정수형 열이 아닌 기본 키를 설정할 수 있습니까? t.string :last_name end 이것이 나에게주는 것은

저는 Rails 마이그레이션을 사용하여 데이터베이스 스키마를 관리하고 있으며 정수가 아닌 값을 기본 키 (특히 문자열)로 사용하려는 간단한 테이블을 만들고 있습니다. 내 문제를 추상화하기 위해 employees직원이 영숫자 문자열로 식별되는 테이블이 있다고 가정 해 보겠습니다 "134SNW".

다음과 같은 마이그레이션에서 테이블을 만들려고했습니다.

create_table :employees, {:primary_key => :emp_id} do |t|
    t.string :emp_id
    t.string :first_name
    t.string :last_name
end

이것이 나에게주는 것은 라인을 완전히 무시하고 t.string :emp_id정수 열로 만든 것처럼 보입니다 . execute호출 에서 SQL을 작성하지 않고도 레일이 PRIMARY_KEY 제약 조건 (PostgreSQL을 사용하고 있음)을 생성하도록하는 다른 방법이 있습니까?

참고 : 문자열 열을 기본 키로 사용하는 것이 최선이 아니라는 것을 알고 있으므로 정수 기본 키를 추가하라는 대답은하지 마십시오. 어쨌든 하나를 추가 할 수 있지만이 질문은 여전히 ​​유효합니다.



답변

불행히도 .NET을 사용하지 않고는 할 수 없다고 판단했습니다 execute.

작동하지 않는 이유

ActiveRecord 소스를 조사하여 다음에 대한 코드를 찾을 수 있습니다 create_table.

에서 schema_statements.rb:

def create_table(table_name, options={})
  ...
  table_definition.primary_key(options[:primary_key] || Base.get_primary_key(table_name.to_s.singularize)) unless options[:id] == false
  ...
end

따라서 create_table옵션 에서 기본 키를 지정하려고하면 지정된 이름으로 기본 키가 생성된다는 것을 알 수 있습니다 (또는 지정되지 않은 경우 id). 테이블 정의 블록 내에서 사용할 수있는 것과 동일한 메서드를 호출하여이를 수행합니다 primary_key..

에서 schema_statements.rb:

def primary_key(name)
  column(name, :primary_key)
end

이것은 지정된 유형의 이름을 가진 열을 생성합니다 :primary_key. 이는 표준 데이터베이스 어댑터에서 다음과 같이 설정됩니다.

PostgreSQL: "serial primary key"
MySQL: "int(11) DEFAULT NULL auto_increment PRIMARY KEY"
SQLite: "INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL"

해결 방법

우리는 이것들을 기본 키 유형으로 사용 execute하기 때문에 정수가 아닌 기본 키를 만들어야합니다 (PostgreSQL serial은 시퀀스를 사용하는 정수입니다).

create_table :employees, {:id => false} do |t|
  t.string :emp_id
  t.string :first_name
  t.string :last_name
end
execute "ALTER TABLE employees ADD PRIMARY KEY (emp_id);"

로 그리고 숀 McCleary 언급 , 당신의 액티브 모델을 사용하여 기본 키를 설정해야합니다 set_primary_key:

class Employee < ActiveRecord::Base
  set_primary_key :emp_id
  ...
end


답변

이것은 작동합니다 :

create_table :employees, :primary_key => :emp_id do |t|
  t.string :first_name
  t.string :last_name
end
change_column :employees, :emp_id, :string

예쁘지 않을 수도 있지만 최종 결과는 정확히 원하는 것입니다.


답변

나는 이것을 처리하는 한 가지 방법이 있습니다. 실행 된 SQL은 ANSI SQL이므로 대부분의 ANSI SQL 호환 관계형 데이터베이스에서 작동합니다. 이것이 MySQL에서 작동하는지 테스트했습니다.

이주:

create_table :users, :id => false do |t|
    t.string :oid, :limit => 10, :null => false
    ...
end
execute "ALTER TABLE users ADD PRIMARY KEY (oid);"

모델에서 다음을 수행하십시오.

class User < ActiveRecord::Base
    set_primary_key :oid
    ...
end


답변

Rails 4.2에서 시도했습니다. 사용자 지정 기본 키를 추가하려면 마이그레이션을 다음과 같이 작성할 수 있습니다.

# tracks_ migration
class CreateTracks < ActiveRecord::Migration
  def change
    create_table :tracks, :id => false do |t|
      t.primary_key :apple_id, :string, limit: 8
      t.string :artist
      t.string :label
      t.string :isrc
      t.string :vendor_id
      t.string :vendor_offer_code

      t.timestamps null: false
    end
    add_index :tracks, :label
  end
end

문서를보고 column(name, type, options = {})다음 행을 읽으십시오.

type: primary_key와, : : 문자열, 텍스트, : 정수 : 플로트 : 진수 : 날짜 : 시간 : 날짜 : 이진 : 매개 변수는 일반적으로 마이그레이션 기본 다음 중 하나입니다 유형 중 하나입니다 부울 .

내가 보여준 것처럼 위의 ides를 얻었습니다. 이 마이그레이션을 실행 한 후의 테이블 메타 데이터는 다음과 같습니다.

[arup@music_track (master)]$ rails db
psql (9.2.7)
Type "help" for help.

music_track_development=# \d tracks
                    Table "public.tracks"
      Column       |            Type             | Modifiers
-------------------+-----------------------------+-----------
 apple_id          | character varying(8)        | not null
 artist            | character varying           |
 label             | character varying           |
 isrc              | character varying           |
 vendor_id         | character varying           |
 vendor_offer_code | character varying           |
 created_at        | timestamp without time zone | not null
 updated_at        | timestamp without time zone | not null
 title             | character varying           |
Indexes:
    "tracks_pkey" PRIMARY KEY, btree (apple_id)
    "index_tracks_on_label" btree (label)

music_track_development=#

그리고 Rails 콘솔에서 :

Loading development environment (Rails 4.2.1)
=> Unable to load pry
>> Track.primary_key
=> "apple_id"
>>


답변

Rails 5에서 할 수있는 일은

create_table :employees, id: :string do |t|
  t.string :first_name
  t.string :last_name
end

create_table 문서를 참조하십시오 .


답변

이 방법을 사용하여 수행 할 수있는 것 같습니다.

create_table :widgets, :id => false do |t|
  t.string :widget_id, :limit => 20, :primary => true

  # other column definitions
end

class Widget < ActiveRecord::Base
  set_primary_key "widget_id"
end

그러면 widget_id 열이 Widget 클래스의 기본 키가되고 개체가 생성 될 때 필드를 채우는 것은 사용자의 몫입니다. before create 콜백을 사용하면 가능합니다.

그래서 라인을 따라 뭔가

class Widget < ActiveRecord::Base
  set_primary_key "widget_id"

  before_create :init_widget_id

  private
  def init_widget_id
    self.widget_id = generate_widget_id
    # generate_widget_id represents whatever logic you are using to generate a unique id
  end
end


답변

저는 Rails 2.3.5를 사용하고 있으며 다음 방법은 SQLite3에서 작동합니다.

create_table :widgets, { :primary_key => :widget_id } do |t|
  t.string :widget_id

  # other column definitions
end

: id => false는 필요하지 않습니다.