Auto increment a non-primary key field in Ruby on Rails - ruby-on-rails

In a RoR migration, how do I auto increment a non-primary-key field? I'd like to do this in the db definition, and not in the model.

You need to 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.

Related

Why Composite Primary Key is not added as a Foreign Key in psql (rails app)?

I am using activerecord-multi-tenant gem for implementing MultiTenancy in my rails project.
Followed instruction from here
I have a User model, Attendance Model which belongs to User, And Company as a tenant.
While I am updating User's primary key(id) to composite key(id, company_id) It is updating.
But when I am trying to update the Foreign key in Attendance models it is only trying to take user_id as a fk and searching for its unique constraint.
Here is the commands i used -
execute 'ALTER TABLE users DROP CONSTRAINT users_pkey;'
execute 'ALTER TABLE users ADD CONSTRAINT users_pkey PRIMARY KEY(id, company_id);'
execute 'ALTER TABLE attendances DROP CONSTRAINT attendances_pkey;'
execute 'ALTER TABLE attendances ADD CONSTRAINT attendances_pkey PRIMARY KEY (id, company_id);'
execute 'ALTER TABLE attendances ADD FOREIGN KEY(user_id, company_id) REFERENCES users(id, company_id);'
The Error i am getting while schema:load
ActiveRecord::StatementInvalid: PG::InvalidForeignKey: ERROR: there is no unique constraint matching given keys for referenced table "users"
: ALTER TABLE "attendances" ADD CONSTRAINT "attendances_user_id_company_id_fkey"
FOREIGN KEY ("user_id")
REFERENCES "users" ("id")
The solution was using structure.sql file.
In schema.rb file it cant always follow the sql command and reflect in the database. So I was getting this error InvalidForeignKey as schema couldn't load the sql command properly.
After moving to structure.sql all the migration were run properly with exact commands inside the files.

providing created_at and updated_at in mass insert for rails with postgres

I'm doing a mass insert a la #chris-heald. If you're interacting with the database directly using raw SQL, do you need to provide the created_at and updated_at fields yourself or will you get that for free from postgres? I'm unclear whether it's Rails or postgres that does the automagical generation here.
ActiveRecord sets the updated_at and created_at values by itself, it doesn't set up the database to supply those values.
If you're doing a bulk insert through SQL then you have some options:
Assign them manually by using Time.now.utc.iso8601 to build the necessary strings. If you need greater precision in your timestamps then you can use strftime instead of iso8601 to build the strings.
Let the database do it by setting default values for those two columns. You could say:
alter table your_table alter column created_at set default now();
alter table your_table alter column created_at set default now();
to add the defaults, then do your bulk import, and then get rid of the defaults using:
alter table your_table alter column created_at drop default;
alter table your_table alter column created_at drop default;
You'd use ActiveRecord::Base.connection.execute to send those ALTER TABLEs into your database if you're doing all this from within Rails.

Creating a PostgreSQL sequence to a field (which is not the ID of the record)

I am working on a Ruby on Rails app. We are using a PostgreSQL database.
There is a table named scores with the following columns:
Column | Type
--------------+-----------------------
id | integer
value | double precision
ran_at | timestamp
active | boolean
build_id | bigint
metric_id | integer
platform_id | integer
mode_id | integer
machine_id | integer
higher_better | boolean
job_id | integer
variation_id | integer
step | character varying(255)
I need to add a sequence to job_id (note: there is no model for job).
How do I create this sequence?
Use CREATE SEQUENCE:
CREATE SEQUENCE scores_job_id_seq; -- = default name for plain a serial
Then add a column default to scores.job_id:
ALTER TABLE scores ALTER COLUMN job_id SET DEFAULT nextval('scores_job_id_seq');
If you want to bind the sequence to the column (so it is deleted when the column is deleted), also run:
ALTER SEQUENCE scores_job_id_seq OWNED BY scores.job_id;
All of this can be replaced with using the pseudo data type serial for the column job_id to begin with:
Safely and cleanly rename tables that use serial primary key columns in Postgres?
If your table already has rows, you may want to set the SEQUENCE to the next highest value and fill in missing serial values in the table:
SELECT setval('scores_job_id_seq', COALESCE(max(job_id), 1)) FROM scores;
Optionally:
UPDATE scores
SET job_id = nextval('scores_job_id_seq')
WHERE job_id IS NULL;
How to check a sequence efficiently for used and unused values in PostgreSQL
Postgres manually alter sequence
How to reset postgres' primary key sequence when it falls out of sync?
The only remaining difference, a serial column is also set to NOT NULL. You may or may not want that, too:
ALTER TABLE scores ALTER COLUMN job_id SET NOT NULL;
But you cannot just alter the type of an existing integer:
ALTER TABLE scores ALTER job_id TYPE serial;
serial is not an actual data type. It's just a notational convenience feature for CREATE TABLE.
In Postgres 10 or later consider an IDENTITY column:
Auto increment table column
So I figured out how to do this using ActiveRecord migrations on Ruby on Rails. I basically used Erwin's commands and help from this page and put them in the migration files. These are the steps:
1.
In the terminal, type:
rails g migration CreateJobIdSequence
rails g migration AddJobIdSequenceToScores
2.
Edit the migration files as follows:
20140709181616_create_job_id_sequence.rb :
class CreateJobIdSequence < ActiveRecord::Migration
def up
execute <<-SQL
CREATE SEQUENCE job_id_seq;
SQL
end
def down
execute <<-SQL
DROP SEQUENCE job_id_seq;
SQL
end
end
20140709182313_add_job_id_sequence_to_scores.rb :
class AddJobIdSequenceToScores < ActiveRecord::Migration
def up
execute <<-SQL
ALTER SEQUENCE job_id_seq OWNED BY scores.job_id;
ALTER TABLE scores ALTER COLUMN job_id SET DEFAULT nextval('job_id_seq');
SQL
end
def down
execute <<-SQL
ALTER SEQUENCE job_id_seq OWNED BY NONE;
ALTER TABLE scores ALTER COLUMN job_id SET NOT NULL;
SQL
end
end
3.
Migrate the database. In the terminal type:
rake db:migrate

How to set auto increment by 1 on a table in your migration script

How to set auto increment by 1 on a table in your migration script
ALTER TABLE Table_name AUTO_INCREMENT = 1;
Is it possible to mention this during table creation or after that, in your DB migration scripts.
Maybe there are better solutions. Otherwise you can run raw SQL statements in migration scripts like this:
ActiveRecord::Base.connection.execute("ALTER TABLE Table_name AUTO_INCREMENT = 1")

Create missing auto increment attribute with rails migration

I'm writing a migration to convert a non-rails app into the right format for rails - one of the tables for some reason does not have auto increment set on the id column. Is there a quick way to turn it on while in a migration, maybe with change_column or something?
You need to execute an SQL statement.
statement = "ALTER TABLE `users` CHANGE `id` `id` SMALLINT( 5 ) UNSIGNED NOT NULL AUTO_INCREMENT"
ActiveRecord::Base.connection.execute(statement)
Note this is just an example. The final SQL statement syntax depends on the database.
If you're on postgesql, a single request won't make it. You'll need to create a new sequence in the database.
create sequence users_id_seq;
Then add the id column to your table
alter table users
add id INT UNIQUE;
Then set the default value for the id
alter table users
alter column id
set default nextval('users_id_seq');
Then populate the id column. This may be quite long if the table has many rows
update users
set id = nextval('users_id_seq');
Hope this helps postgresql users...
The Postgres answer by #jlfenaux misses out on the serial type, which does all of it for you automatically:
ALTER TABLE tbl add tbl_id serial;
More details in this related answer.

Resources