Does HABTM jointable needs index? - ruby-on-rails

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

Related

ArgumentError: Index name ... is too long; the limit is 62 characters

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

Creating a many to many relationship in rails 4

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.

Rails: "t.references" not working when creating index

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

Adding unique: true for add_column and add_index in Active Record

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

Rails create_table query

I am a beginner in Rails. In the following code,there is an id which is set as false. What's the meaning of it?
class CreateCoursesStudents < ActiveRecord::Migration
def self.up
create_table :courses_students, **:id => false** do |t|
t.integer :course_id,:null => false
t.integer :student_id, :null => false
end
# Add index to speed up looking up the connection, and ensure # we only
enrol a student into each course once
add_index :courses_students, [:course_id, :student_id], :unique => true
end
def self.down
remove_index :courses_students, :column => [:course_id, :student_id]
drop_table :courses_students
end
end
Thanks
:id => false defines a table with no primary key, which is useful e.g. when you create a join table for a many-to-many relationship.
:null=>false indicates that the field in question cannot be null for any row that gets created in the the courses_students table.

Resources