I created a scaffold with this command (Rails 5.2.1.1):
rails g scaffold EmailAddress value:string:index
email_address_type:references
email_addressable:references{polymorphic}
position:integer
which resulted in this migration file:
class CreateEmailAddresses < ActiveRecord::Migration[5.2]
def change
create_table :email_addresses do |t|
t.string :value
t.references :email_address_type, foreign_key: true
t.references :email_addressable, polymorphic: true
t.integer :position
t.timestamps
end
add_index :email_addresses, :value
end
end
Unfortunately this raises the following error on rails db:migrate:
Caused by:
ArgumentError: Index name
'index_email_addresses_on_email_addressable_type_and_email_addressa...'
on table 'email_addresses' is too long; the limit is 62 characters
I understand the problem and the error. I'm wondering what the best solution is because the index is not set explicity by add_index but by some background magic.
As Wintermeyer says is one solution, there is another way at least I find smoother to use.
t.references :email_address_type, foreign_key: true,
index: { name: "addressable_index" }
Through this you dont get a bunch of add_index rows in your migration. This helps if you ever have a large migration and need to find a specific index quickly. This is just my personal opinion, Wintermeyer solution is also a working fix!
index: false is the solution for this problem. Followed by an add_index at the bottom. Here is the migration:
class CreateEmailAddresses < ActiveRecord::Migration[5.2]
def change
create_table :email_addresses do |t|
t.string :value
t.references :email_address_type, foreign_key: true
t.references :email_addressable, polymorphic: true, index: false
t.integer :position
t.timestamps
end
add_index :email_addresses, :value
add_index :email_addresses, [:email_addressable_type,
:email_addressable_id],
name: 'email_addressable_index'
end
end
Related
I'm using rails 5, and I've installed the gem and tried to run the migration, but I'm getting this error:
Index name 'index_rates_on_rater_id' on table 'rates' already exists
Does anyone know why this exists? This is a new site and started fresh just adding devise gem.
This is the migration file that wouldn't complete on execution rails db:migrate
class CreateRates < ActiveRecord::Migration[5.1]
def self.up
create_table :rates do |t|
t.belongs_to :rater
t.belongs_to :rateable, :polymorphic => true
t.float :stars, :null => false
t.string :dimension
t.timestamps
end
add_index :rates, :rater_id
add_index :rates, [:rateable_id, :rateable_type]
end
def self.down
drop_table :rates
end
end
The gem creates a migration that does not work in later versions of rails. In Rails 5 when you use the belongs_to and references macros they create indices and foreign keys by default.
All you really need is this:
class CreateRates < ActiveRecord::Migration[5.1]
def self.change
create_table :rates do |t|
t.belongs_to :rater
t.belongs_to :rateable, polymorphic: true
t.float :stars, null: false
t.string :dimension
t.timestamps
end
add_index :rates, [:rateable_id, :rateable_type]
end
end
You don't need up and down since Rails is smart enough to know how to rollback this migration.
How can I create a relationship table in my migration class that both references are used in an unique index?
class CreateDiagnosticHypotheses < ActiveRecord::Migration
def change
create_table :diagnostic_hypotheses, :id => false do |t|
t.references :accident_indication, index: true
t.references :forms, index: true
t.timestamps null: false
end
add_foreign_key :diagnostic_hypotheses, :accident_indications
add_foreign_key :diagnostic_hypotheses, :forms, column: :diagnostic_hypothesis_id
end
end
When I run rake db:migrate it tries to create separate indexes. How can I create just one unique index with both :accident_indication and :forms references?
You can create unique composite index:
class CreateDiagnosticHypotheses < ActiveRecord::Migration
def change
create_table :diagnostic_hypotheses, :id => false do |t|
t.references :accident_indication
t.references :forms
t.timestamps null: false
end
add_index :diagnostic_hypotheses, [:accident_indication_id, :forms_id], :unique => true
add_foreign_key :diagnostic_hypotheses, :accident_indications
add_foreign_key :diagnostic_hypotheses, :forms, column: :diagnostic_hypothesis_id
end
end
I didn't try it myself, however, but I think you've got the idea.
Is it necessary to add_index on HABTM join table? I use t.belongs_to (aka t.references). Here is code
class CreateCohortsUsersTable < ActiveRecord::Migration
def change
create_table :cohorts_users, :id => false do |t|
t.belongs_to :cohort
t.belongs_to :user
end
add_index :cohorts_users, :cohort_id # Do I need this?
add_index :cohorts_users, :user_id # Do I need this?
end
end
It's usually a good idea to add a unique index on both columns:
add_index :cohorts_users, [:cohort_id, :user_id], unique: true
class CreateBallots < ActiveRecord::Migration
def change
create_table :ballots do |t|
t.references :user
t.references :score
t.references :election
t.string :key
t.timestamps
end
add_index :ballots, :user
add_index :ballots, :score
add_index :ballots, :election
end
end
results in:
SQLite3::SQLException: table ballots has no column named user: CREATE INDEX "index_ballots_on_user" ON "ballots" ("user")/home/muhd/awesomevote/db/migrate/20130624024349_create_ballots.rb:10:in `change'
I thought t.references was supposed to handle that for me?
You forgot to add "_id" like this:
add_index :ballots, :user_id
or, if you want it indexed automatically:
t.references :user, index: true
More info: add_index , references
HTH
The answer above is correct, but be aware that:
t.references :user, index: true is only available in Rails 4.0 & up.
In earlier versions of Rails (3.x), index: true will fail silently, leaving you without an index on that table. For Rails 3.2.x & down, use the older syntax:
add_index :ballots, :user_id
Or in full using your example:
class CreateBallots < ActiveRecord::Migration
def change
create_table :ballots do |t|
t.references :user
t.references :score
t.references :election
t.string :key
t.timestamps
end
add_index :ballots, :user_id
add_index :ballots, :score_id
add_index :ballots, :election_id
end
end
Even though my application isn't gonna allow a user to key in a location, I wanted to enforce a uniqueness on city in the database. Since my Rails app will be searching on the city column, I would like to add an index on the city column as well but was wondering if it matters adding unique: true on the index as well. Is this repetitive? If this doesn't make sense, I would really appreciate it if you could explain why.
class CreateLocations < ActiveRecord::Migration
def change
create_table :locations do |t|
t.string :city, unique: true
t.string :state
t.timestamps
end
add_index :locations, :city, unique: true
end
end
Using Rails 4, you can provide: index param a hash argument
class CreateLocations < ActiveRecord::Migration
def change
create_table :locations do |t|
t.string :city, index: {unique: true}
t.string :state
t.timestamps
end
end
end
As far as I know the unique option in the create_table block is actually not supported and doesn't do anything, see TableDefinition. To create the unique index, you need to call the method add_index the way you do now. Note that a unique index is both for uniqueness and for searching etc., there's no need to add two indexes on the same column.
You can specify unique index while scaffolding:
rails generate model Locations city:string:uniq state:string
This will create Model, Spec, Factory and this migration:
class CreateLocations < ActiveRecord::Migration
def change
create_table :locations do |t|
t.string :city
t.string :state
t.timestamps null: false
end
add_index :locations, :city, unique: true
end
end
Rails knows what it's doing - nothing more is required.
Add: index: { unique: true }
Example:
class AddUsernameToUsers < ActiveRecord::Migration[6.1]
def change
add_column :users, :username, :string, null: false, index: { unique: true }
end
end