Используя направляющие, как я могу установить свой первичный ключ, чтобы не быть введенным целым числом столбцом?

Bash имеет выбор с этой целью.

select result in Yes No Cancel
do
    echo $result
done

85
задан Rudd Zwolinski 29 July 2009 в 14:15
поделиться

5 ответов

Unfortunately, I've determined it's not possible to do it without using execute.

Why it doesn't work

By examining the ActiveRecord source, we can find the code for create_table:

In 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

So we can see that when you try to specify a primary key in the create_table options, it creates a primary key with that specified name (or, if none is specified, id). It does this by calling the same method you can use inside a table definition block: primary_key.

In schema_statements.rb:

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

This just creates a column with the specified name of type :primary_key. This is set to the following in the standard database adapters:

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

The workaround

Since we're stuck with these as the primary key types, we have to use execute to create a primary key that is not an integer (PostgreSQL's serial is an integer using a sequence):

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);"

And as Sean McCleary mentioned, your ActiveRecord model should set the primary key using set_primary_key:

class Employee < ActiveRecord::Base
  set_primary_key :emp_id
  ...
end
107
ответ дан 24 November 2019 в 08:14
поделиться

, вы должны использовать опцию: id => false

create_table :employees, :id => false, :primary_key => :emp_id do |t|
    t.string :emp_id
    t.string :first_name
    t.string :last_name
end
2
ответ дан 24 November 2019 в 08:14
поделиться

Похоже, что это можно сделать, используя такой подход:

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
8
ответ дан 24 November 2019 в 08:14
поделиться

У меня есть один способ справиться с этим. Выполняемый 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

18
ответ дан 24 November 2019 в 08:14
поделиться

Я использую Rails 2.3.5, и мой следующий способ работает с SQLite3

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

  # other column definitions
end

Нет необходимости в : id => ложь.

8
ответ дан 24 November 2019 в 08:14
поделиться
Другие вопросы по тегам:

Похожие вопросы: