How to specify a default primary key with no auto increment - ruby-on-rails

class Sizes < ActiveRecord::Migration
def self.up
create_table :sizes do |t|
t.integer :size, :null => false
end
end
def self.down
drop_table :sizes
end
end
class Sizes < ActiveRecord::Migration
def self.up
Size.create(:id => 1, :size => 5)
Size.create(:id => 2, :size => 10)
end
def self.down
Size.delete_all
end
end
While trying to populate the db using the command rake db:migrate and i got the following output
select * from sizes;
id size
1 5
2 10
After I rollback the entire tables from db using the command called rake db:rollback. Once again I re-populated the db and now it seems to be the following
select * from sizes;
id size
3 5
4 10
I don't want the primary key to change, how do I stop specifying the auto increment capability or specify the ability to associate a hard-coded primary key id, so that it remains the same.

Try this
create_table(:id => false) do |t|
t.integer :own_id, :options => 'PRIMARY KEY'
end
Hope this helps

rake db:rollback will take you one step back, which in your case will delete the sizes you created (1 => 5, 2 => 10)
You could go one more step back which will drop the table and then run migration's again, recreating the table and the data.
Alternately if you'd only like to go back one step then you can execute some custom sql in self.down method
def self.down
Size.delete_all
execute <<-SQL
ALTER TABLE Sizes AUTO_INCREMENT=0
SQL
end
You can also try
create_table :sizes, :options => "auto_increment = 0" do |t|
...
end

Related

Insert data in migration if it does not exist

I have the following migration:
Sequel.migration do
up do
create_table :user_settings do
primary_key :id
String :signature, null: true, text: true
end
alter_table :user_settings do
add_foreign_key :user_id, :users, null: false, on_delete: :cascade
add_index :user_id
end
end
down do
drop_table :user_settings
end
end
This will add default user settings.
The problem I have is that I want to create a row in the user_settings table for every user who is currently in the database that does not have a row, prior to this migration.
I want to check if each user has a row with a a matching user_id in the database and if not, I want to insert some default values.
How can I do this in a migration?
Normally, this kind of things are done using rake task but you need in the migration. I guess you have added the association in the User and UserSetting model and it will be has_one association. You need to create a new migration file
def up
users = User.includes([:user_setting]).where(:user_setting => {:user_id => nil})
users.each do |user|
user.create_user_setting
# OR you can write
# UserSetting.create({:user_id => user.id, :signature => 'your-custom-text'})
end
end
I ended up with this:
Sequel.migration do
up do
existing_settings = SequelAdapter::UserSettings.select(:user_id).to_a
SequelAdapter::User.exclude(id: existing_settings).each do |user|
SequelAdapter::UserSettings.create({user_id: user.id})
end
end
end
Thanks #bachan Smruty who pointed me in the right direction but there is no includes method.

How can I add a column to reference to another table on RoR?

Here is the Customer:
class CreateCustomer < ActiveRecord::Migration
def self.up
create_table :customers do |t|
t.column :email, :string, :null => false
end
end
def self.down
drop_table :customers
end
end
And this is the customer Info:
class CustomerInfo < ActiveRecord::Migration
def self.up
create_table :statuses do |t|
t.column :statuses, :string, :null => false
end
end
def self.down
drop_table :status
end
end
What I would like to do is the customer and customer Info have a one to one relationship. How can I do it in a new migration? thank you.
When you want a 1 to 1 in Rails, you have to decide which one of the models will store the foreign key. In your case, you probably want status to store the fk, so add an integer column called customer_id to the status table. Then you can add the has_one/belongs_to on Customer and Status. belongs_to always goes on the model with the foreign key.
Also I'm not sure if Rails will like you calling your table with the singular name, so you will probably have to do some extra work if you really want to call it 'status' instead of 'statuses'
You can try following thing in your next migration
add_column :customer_infos , :customer_id , :integer ,:references=>"customers" , :null=>:true
Then you can add the has_one/belongs_to on Customer and Cusomer_infos .
You can also execute an SQL statement.
statement = "ALTER TABLE users CHANGE id id SMALLINT( 5 ) UNSIGNED NOT NULL AUTO_INCREMENT" ActiveRecord::Base.connection.execute(statement)
you can entry manually in your migration
Note this is just an example. The final SQL statement syntax depends on the database.

Plural to Singular conversion trouble in Rails Migrations?

I'm a beginner at Ruby On Rails and am trying to get a migration to work with the name Priorities
So, here is the code I use in my migration:
class Priorities < ActiveRecord::Migration
def self.up
create_table :priorities do |t|
t.column :name, :string, :null => false, :limit => 32
end
Priority.create :name => "Critical"
Priority.create :name => "Major"
Priority.create :name => "Minor"
end
def self.down
drop_table :priorities
end
end
This results in the following error though:
NOTICE: CREATE TABLE will create implicit sequence "priorities_id_seq" for serial column "priorities.id"
NOTICE: CREATE TABLE / PRIMARY KEY will create implicit index "priorities_pkey" for table "priorities"
rake aborted!
An error has occurred, this and all later migrations canceled:
uninitialized constant Priorities::Priority
Is this some problem with turning ies to y for converting something plural to singular?
Also, the full --trace log is here: http://pastebin.com/w6usBSng
Using the following command, I was able to get the same error:
script/generate migration priorities
This is happening because you don't have a Priority class. You probably intended on running this command:
script/generate model Priority name:string
This fixes the problem
EDIT
Apparently you don't want a Priority model. In this situation, I have no idea why, but you can circumvent this by using execute in your migration methods.
Try something like this:
class CreatePriorities < ActiveRecord::Migration
def self.up
create_table :priorities do |t|
t.column :name, :string, :null => false, :limit => 32
end
execute "insert into priorities (name) values ('Critical');"
execute "insert into priorities (name) values ('Major');"
execute "insert into priorities (name) values ('Minor');"
end
def self.down
drop_table :priorities
end
en
d
Yes. Your table name is Priorities and Model name also (i guess) Priorities. So it get crashed at "Priority.create :name => "Critical".
This should be
class Priorities < ActiveRecord::Migration
def self.up
create_table :priorities do |t|
t.column :name, :string, :null => false, :limit => 32
end
Priorities.create :name => "Critical" #Where "Priorities" is your Model Name
Priorities.create :name => "Major"
Priorities.create :name => "Minor"
end
def self.down
drop_table :priorities
end
end

How do I add some inserts in rails migration?

After creating a table (by migration), I want to insert some entries directly. How must I write a migration for this?
thanks
Don't. If you're looking for seed data, you should use db/seeds.rb and rake db:seed instead. More info in this Railscast.
Side note: Always make sure that the code in db/seeds.rb is idempotent. i.e. It should always be safe to re-run your seeds.
But, if you must insert or modify data inside a migration (there are legitimate use-cases for this), it's best to use SQL statements instead. Your model class isn't guaranteed to still be around in the same form in a future version of your application, and running the migrations from scratch in the future might yield errors if you reference the model class directly.
execute "insert into system_settings (name, label, value) values ('notice', 'Use notice?', 1)"
Update:
This is the right answer: https://stackoverflow.com/a/2667747/7852
Here's an example from ruby on rails api:
class AddSystemSettings < ActiveRecord::Migration
# create the table
def self.up
create_table :system_settings do |t|
t.string :name
t.string :label
t.text :value
t.string :type
t.integer :position
end
# populate the table
SystemSetting.create :name => "notice", :label => "Use notice?", :value => 1
end
def self.down
drop_table :system_settings
end
end
Edit: PLEASE NOTE - Posters above are correct, you should not populate the DB inside migrations. Don't use this to add new data, only to modify data as part of changing the schema.
For many things, using raw SQL will be preferable, but if you need to insert data as part of a migration (for instance, doing data conversion when breaking out a table into multiple tables), and you want some default AR stuff like convenient DB-independent escaping, you can define a local version of the model class:
class MyMigrationSucksALittle < ActiveRecord::Migration
class MyModel < ActiveRecord::Base
# empty guard class, guaranteed to have basic AR behavior
end
### My Migration Stuff Here
### ...
end
Note that this works best for simple cases; since the new class is in a different namespace (MyMigrationSucksALittle::MyModel), polymorphic associations declared in the guard model won't work correctly.
A somewhat more detailed overview of available options is located here: http://railsguides.net/2014/01/30/change-data-in-migrations-like-a-boss/
create a new migration file like
047_add_rows_in_system_settings.rb
class AddRowsInAddSystemSettings < ActiveRecord::Migration
def self.up
SystemSetting.create{:name => "name1", :label => "Use notice?", :value => 1}
SystemSetting.create{:name => "name2", :label => "Use notice?", :value => 2}
end
def self.down
SystemSetting.delete_all
end
end
OR
while creating table
046_system_settings.rb
class AddSystemSettings < ActiveRecord::Migration
def self.up
create_table :system_settings do |t|
t.string :name
t.string :label
t.text :value
t.string :type
t.integer :position
end
SystemSetting.create :name => "notice", :label => "Use notice?", :value => 1
end
def self.down
drop_table :system_settings
end
end
Ref:- http://api.rubyonrails.org/classes/ActiveRecord/Migration.html

In a Rails migration, is it possible to indicate that a newly added column should be before or after an existing column in the table?

Let's say I create a table in a Rails migration, specifying to omit the ID column:
create_table :categories_posts, :id => false do |t|
t.column :category_id, :integer, :null => false
t.column :post_id, :integer, :null => false
end
Later I decide I want to add an ID column as a primary key so I create a new migration:
class ChangeCategoriesToRichJoin < ActiveRecord::Migration
def self.up
add_column :categories_posts, :id, :primary_key
end
def self.down
remove_column :categories_posts, :id
end
end
But when I look at the table after I migrate, it looks like this:
category_id
post_id
id
The id column is in the last position in the table, whereas normally an id column would be first.
Is there a way to change the ChangeCategoriesToRichJoin migration to insist on the id column being created BEFORE the category_id column in the table?
Or do I need to drop the table and add the column in the "create table" definition?
Use :after => :another_column_name, e.g.:
change_table :users do |t|
t.integer :like_count, :default => 0, :after => :view_count
end
I haven't been able to put the columns in order, myself, but with Rails you can rollback, alter the old migration file to add the new columns in the order you want, then re-migrate up the old migration including the new field. It's not exactly ideal, but the ability to migrate and rollback easily, it can work if you're OCD enough to require column order. :P
I am not an expert, but I've read a lot of Rails documentation (and very recently) and can't recall finding a solution for this.

Resources