Problems setting a custom primary key in a Rails 4 migration
Take a look at this answer. Try to execute "ALTER TABLE shareholders ADD PRIMARY KEY (uid);"
without specifying primary_key parameter in create_table block.
I suggest to write your migration like this (so you could rollback normally):
class CreateShareholders < ActiveRecord::Migration
def up
create_table :shareholders, id: false do |t|
t.integer :uid, limit: 8
t.string :name
t.integer :shares
t.timestamps
end
execute "ALTER TABLE shareholders ADD PRIMARY KEY (uid);"
end
def down
drop_table :shareholders
end
end
UPD: There is natural way (found here), but only with int4 type:
class CreateShareholders < ActiveRecord::Migration
def change
create_table :shareholders, id: false do |t|
t.primary_key :uid
t.string :name
t.integer :shares
t.timestamps
end
end
end
Change Primary Key Issue Rails 4.0
The answer seemed to be that the OP separated the migration into 3 files:
1. Remove `:id` column
2. Rename `:contractId` column to `:id`
3. run `execute "ALTER TABLE contracts ADD PRIMARY KEY (id);"`
This allowed the OP to successfully run the migration
Some other resources:
- Using Rails, how can I set my primary key to not be an integer-typed column?
- Problems setting a custom primary key in a Rails 4 migration
Specify custom primary key in migration
create_table(:my_table, :primary_key => 'userID') do |t|
# Primary key column will be created automatically
# Do not create here
# t.column :userID, :integer, :null => false
...
end
Or
create_table :my_table, {:id => false} do |t|
t.integer :userID
t.string :apikey
t.integer :characterID
t.timestamps
end
execute "ALTER TABLE my_table ADD PRIMARY KEY (userID);"
And don't forget to put this line somewhere in model:
set_primary_key :userID
How to set primary key in ruby on rails migration?
Don't do this. Use the built-in id
field as the primary key. If you're going to use Rails, you should build your app the "Rails way" unless you have very good reason not to.
If you really want to do this, you can pass a :primary_key
option to create_table
:
create_table :customers, :primary_key => :idClient do |t|
# ...
end
You'll also need to tell your model the name of its primary key via self.primary_key = "idClient"
Rails Model - custom primary key with ID as a custom column
I'd avoid using id
this way by renaming it to something else. In rails id
is whatever the @primary_key is set to. There is a whole module dedicated to it, that defines id attribute methods:
https://api.rubyonrails.org/classes/ActiveRecord/AttributeMethods/PrimaryKey.html
These methods can be overridden, but shouldn't:
class Car < ApplicationRecord
self.primary_key = "auto_id"
def id= value
_write_attribute("id", value)
end
def id
_read_attribute("id")
end
end
"id" is hardcoded in write_attribute to use primary_key, so we can't use write_attribute to set id attribute itself.
Also, id
methods are used in other places. Overriding them is a bad idea.
>> Car.create(id: "99")
=> #<Car:0x00007f723e801788 auto_id: nil, id: "99">
# ^
# NOTE: Even though car has been saved, `auto_id` is still `nil`
# but only in `car` object. Because we have overridden
# `id`, primary key is read from `id` column and then `id`
# attribute is set in `id=`. `auto_id` is bypassed.
>> Car.last
=> #<Car:0x00007f774d9e8dd0 auto_id: 1, id: "99">
# NOTE: Other methods are broken whenever `id` is used
>> Car.last.to_key
=> ["99"]
>> Car.last.to_gid
=> #<GlobalID:0x00007f774f4def68 @uri=#<URI::GID gid://stackoverflow/Car/99>>
A better way is to not touch id
methods:
class Car < ApplicationRecord
self.primary_key = "auto_id"
def id_attribute= value
_write_attribute("id", value)
end
def id_attribute
_read_attribute("id")
end
end
>> car = Car.create(id_attribute: "99")
=> #<Car:0x00007fb1e44d9458 auto_id: 2, id: "99">
>> car.id_attribute
=> "99"
>> car.id
=> 2
>> car.auto_id
=> 2
Overriding primary key column in Rails 4 and SQLite
OK, I've found the solution for myself: execute each SQL statement independently:
execute "DROP TABLE requests;"
execute "CREATE TABLE requests (id TEXT NOT NULL PRIMARY KEY, name TEXT);"
EDIT
A more elegant solution to prevent creating the table by hand, specially when the table has many columns and we want to keep it synced with the call to ActiveRecord's create_table
method:
#Get from SQLite's master table the SQL statement that creates the table,
#and that was initially generated by Rails
sql = select_value("SELECT sql FROM sqlite_master WHERE type='table' AND name='requests'")
#Only replace the definition of the 'id' column by adding the PRIMARY KEY
#constraint
sql.gsub!(/"id" [^,]+/, '"id" VARCHAR(255) NOT NULL PRIMARY KEY')
#Delete the original table
drop_table :requests
#Create the table again
execute sql
Rails Migration Create Table Primary Key
I suppose you're using mySQL, so here is what you can try
create_table :global_feeds, {:id => false} do |t|
t.string :guid
t.text :title
t.text :subtitle
t.timestamps
end
execute "ALTER TABLE global_feeds ADD PRIMARY KEY (guid);"
If you're not on mySQL you should change the query in the execute
command to work on your DB engine. I'm not sure if you can do that on SQLite though. And don't forget to put this line somewhere in global_feed.rb model:
set_primary_key :guid
Anyway you're getting the most out of Rails while you're sticking to its conventions. Changing primary key name and type might not be a very good idea.
Rails 4.2.7 mysql set two custom primary key
Having two primary key in a single table doesn't make sense. If you really have two keys that will always uniquely identify data, you can have a combined key of those two keys, and that combined key will act as a primary key.
Here's is how you can accomplish this in Rails:
class CreateLikes < ActiveRecord::Migration
create_table :likes, id: false do |t|
t.string :ip, limit: 39
t.references :post, index: true, foreign_key: true
t.timestamps null: false
end
execute "ALTER TABLE likes ADD PRIMARY KEY (ip,post_id);"
end
And in your Like
model:
class Like < ActiveRecord::Base
self.primary_keys = :ip, :post_id
end
How to change primary key in rails migration file?
You could execute arbitrary SQL in your migration:
execute "ALTER TABLE `products` DROP PRIMARY KEY"
and then add the new column:
add_column :products, :id, :primary_key
See:
Remove Primary Key in MySQL
how to add a primary key to a table in rails
http://thinkwhere.wordpress.com/2009/05/09/adding-a-primary-key-id-to-table-in-rails/
http://api.rubyonrails.org/classes/ActiveRecord/Migration.html
Related Topics
Trying to Install Ruby-Filemagic on Snow Leopard Using Brew Rather Than Ports
Using Rbenv Doesn't Work with Sudo
Show Full Path Name of the Ruby File When It Get Loaded
Getting Uninitialized Constant Error When Trying to Run Tests
Hacking Activerecord: Add Global Named Scope
How to Create Symbol (Hash Key) from Association, Using New Ruby (1.9) Hash Syntax
What's the Point of the Prefix? Operator in Ruby 1.9
When to Use Nested Classes and Classes Nested in Modules
Ruby Metaprogramming: Dynamic Instance Variable Names
In Ruby, How to Make a Hash from an Array
Rails: Encoding Woes with Serialized Hashes Despite Utf8
Ruby Hash Autovivification (Facets)
What's the Point of Freezing Your Rails Version/Gems
Howto Rank Items by Balance in Ruby on Rails
How Does Require Rubygems Help Find Rubygem Files