web-dev-qa-db-ja.com

2列に基づいて一意の主キーを定義する

「id」と「language」の2つの列に基づいてレコードの一意のキーを定義したい

ユーザーが次の文字列を送信できるようにするには:id = 1 language = en value = blabla english id = 1 language = fr value = blabla french

Set_primary_keyとadd_indexも使用しようとしましたが、機能しませんでした(add_index:words、["id"、 "language_id"]、:unique => true)

私は次のモデルを持っています:

class Word < ActiveRecord::Base
  belongs_to :dictionnary
  belongs_to :language

  attr_accessible :lang, :rev, :value, :dictionnary_id, :language_id

  validates :value, :uniqueness => true

end  

この

class Language < ActiveRecord::Base
    has_many :words

    attr_accessible :lang
end
34
Stéphane V

add_index :words, ["id", "language_id"], :unique => true

動作するはずです。データベースにすでに一意でないデータがいくつかあり、インデックスを作成できない場合がありますか?しかし(IDは常に一意であるため、@ Doonが冗長であることに気づいたように)。したがって、2つの列に主キーを作成する必要があります。

Rails=で2列の主キーを定義するには:

create_table :words, {:id => false} do |t|
  t.integer :id
  t.integer :language_id
  t.string :value
  t.timestamps
end
execute "ALTER TABLE words ADD PRIMARY KEY (id,language_id);"

そして、このgemを使用してモデルにprimary_keyを設定します。 http://rubygems.org/gems/composite_primary_keys

class Word < ActiveRecord::Base
    self.primary_keys = :id,:language_id
end
49
rogal111

Rails 5では、次のことができます。

create_table :words, primary_key: %i[id language_id] do |t|
  t.integer :id
  t.integer :language_id
  t.string :value
  t.timestamps
end

Wordモデルにprimary_key属性を設定する必要もありません。

6
Vadim

私のコメントで述べたように、あなたはRailsと戦うことになり、箱から出して実際にサポートされていません。あなたは http:// compositekeys .rubyforge.org Railsで複合主キーを実行する方法を提供します。まだ必要がなかったので、使用していません(通常、複合キーのようなものがある場合)主キーと結合されたペアの一意のインデックス(HABTM)のない結合テーブル。

1
Doon

モデル

class User < ActiveRecord::Base
  has_secure_password
  self.primary_keys = :name
end

移行

class CreateUsers < ActiveRecord::Migration
  def change
    create_table :users do |t|
      t.string :name, null: false
      t.string :emailid
      t.string :password_digest
      t.integer :locked, :default => 0
      t.text :secretquestion
      t.string :answer

      t.timestamps null: false
    end
    add_index :users, :name, :unique => true
  end
end

このテーブルを取得します

image

1
Bhavnesh

@ rogal111が言ったように、主キーが既に存在する場合は、これを実行する必要があります。

ALTER TABLE sections DROP PRIMARY KEY, ADD PRIMARY KEY(id, workspace_id, section_key);
0
Son Tr.

ユースケースに応じて、 composite key gem を試してみることができます。これにより、複合主キーを定義し、ActiveRecordがこの種のモデルを処理できるようになります(このモデルへの関連付けに役立ちます。 url_forヘルパーなど)。

したがって、このモデルを他のRailsモデルとして使用することを計画している場合、gemは大いに役立ちます。

0
Michael

サイトをRailsに移行するときに、同様の問題に直面しました。サイトが利用可能な各言語のテキストデータを格納するテーブルがあるため、次のようなものがありました。

CREATE TABLE Project_Lang(
    project_id INT NOT NULL,
    language_id INT NOT NULL,
    title VARCHAR(80),
    description TEXT,

    PRIMARY KEY pk_Project_Lang(project_id, language_id),

    FOREIGN KEY fk_Project_Lang_Project(project_id)
        REFERENCES Project(project_id)
        ON DELETE RESTRICT ON UPDATE CASCADE,

    FOREIGN KEY fk_Project_Lang_Language(language_id)
        REFERENCES Language(language_id)
        ON DELETE RESTRICT ON UPDATE CASCADE
)ENGINE = InnoDB DEFAULT CHARACTER SET = utf8 DEFAULT COLLATE = utf8_spanish_ci;

しかし、Railsはすぐに使用できる複合主キーを処理しないため、テーブルの構造を変更して、それが独自の主キーを持つようにしました。

CREATE TABLE Project_Lang(
    project_lang_id INT NOT NULL PRIMARY KEY AUTO_INCREMENT,
    project_id INT NOT NULL,
    language_id INT NOT NULL,
    title VARCHAR(80),
    description TEXT,

    UNIQUE INDEX(project_id, language_id),

    FOREIGN KEY fk_Project_Lang_Project(project_id)
        REFERENCES Project(project_id)
        ON DELETE RESTRICT ON UPDATE CASCADE,

    FOREIGN KEY fk_Project_Lang_Language(language_id)
        REFERENCES Language(language_id)
        ON DELETE RESTRICT ON UPDATE CASCADE
)ENGINE = InnoDB DEFAULT CHARACTER SET = utf8 DEFAULT COLLATE = utf8_spanish_ci;

また、重複レコードが挿入されないように、以前に複合主キーを作成した列に一意のインデックスを作成しました。それから私のRailsモデルで私は簡単にできました:

self.primary_key = "project_lang_id"

そして、それはトリックをしました。私が望んだものではありませんが、フレームワークと戦うよりはましです。

0
Sergio