Does rename_column take care of indexes? - ruby-on-rails

Say, we have something like this:
add_column :users, :single, :boolean
add_index :users, :single
and then later we do
rename_column :users, :single, :married
Will ActiveRecord and/or the database handle the renaming of the index as well or do I have to manually drop the index and add it again?

For PostgreSQL, rename_column is implemented as a simple ALTER TABLE ... RENAME COLUMN ... and that does preserve the indexes.
The MySQL versions (both of them) do an ALTER TABLE ... CHANGE ... and that also preserves the indexes.
The SQLite version appears to copy the entire table (with indexes), drop the old one, and then copy the copy back to the original table name. The copying does appear to handle the column rename while copying the indexes:
def copy_table(from, to, options = {})
#...
copy_table_indexes(from, to, options[:rename] || {})
and inside copy_table_indexes:
columns = index.columns.map {|c| rename[c] || c }.select do |column|
to_column_names.include?(column)
end
So, the standard drivers will preserve your indexes when you do a rename_column and the SQLite driver goes to some effort to do so.
The API documentation doesn't specify any particular behavior though so other drivers may do other things. The closest the documentation comes to saying anything about indexes is this in active_record/migration.rb:
rename_column(table_name, column_name, new_column_name): Renames a column but keeps the type and content.
I think any driver would preserve the indexes but there's no guarantee; a driver writer would certainly be foolish not to preserve the indexes.
This isn't a definitive or authoritative answer but your indexes should be preserved if you use the standard PostgreSQL, MySQL (either one of them), or SQLite drivers.
Note that even though the index itself survives the column renaming there's no guarantee that the index name will be changed. This shouldn't be a problem unless you're doing something (such as manually dropping it) that cares about the index name rather than what columns are involved.
The above behavior changed in Rails 4:
In Rails 4.0 when a column or a table is renamed the related indexes are also renamed. If you have migrations which rename the indexes, they are no longer needed.
So ActiveRecord will automatically rename indexes to match the new table or column names when you rename the table or column. Thanks to sequielo for the heads-up on this.

Related

Rails migrations indexing

What is the difference between these two methods of adding indexes:
add_index :juice_ingredients, %i(juice_id ingredient_id)
and:
add_index :juice_ingredients, :juice_id
add_index :juice_ingredients, :ingredient_id
Moreover, do I need to explicitly create join table or just add_reference is enough?
The first will create a single index on two columns. The second will create two indexes, each on their own column. Which is better depends on your application, the database, and the queries you run. To figure out which you need to read up on "query optimization" for your database.
The difference is that the first statement creates a multi-column index (also called composite index), the second creates two single-column indexes.
Both versions results in the columns :juice_id and :ingredient_id being indexed at database level. However, they behave a little bit differently.
In order to better understand how, you need to have some knowledge of what is a database index and what you can use it for.
Composite indexes are recommended if you are likely to query the database using both columns in the same query. Moreover, you can use an index with an unique constraint to make sure that no duplicate records are created for a specific key, or combination of key.
Here's some additional articles:
http://www.postgresql.org/docs/8.2/static/indexes-multicolumn.html
https://devcenter.heroku.com/articles/postgresql-indexes#multi-column-indexes

Rails4 create join tabel no need to add primary key in Migration?

I use this command :
rails g migration CreateJoinTableUserPloy user ploy
And i check the Migration file:
create_join_table :Users, :Posts do |t|
#t.index [:user_id, :ploy_id]
#t.index [:ploy_id, :user_id]
end
There are 2 index is be commented by defualt.
Then i run this command:
rake db:migrate
Then i check my database structure
And i not seen primary key, Does it mean that join tabel no need add index and primary key in database structure?
Consistent with http://meta.serverfault.com/a/1931, I'm going to respond to this as an answer, even though some of the information is in the comment thread.
There is no primary key in a Rails-generated join table (i.e. as created by create_join_table, which is used by migrations with JoinTable in their name) and Rails has no inherent requirement for one. That's because most pure join tables are only accessed by the id's of the joined tables, in which case primary_key is unnecessary. You can, of course, add and designate a primary key column if you wish.
Rails does not support multiple column primary_keys, although there are multiple gems that provide that support, such as https://github.com/composite-primary-keys/composite_primary_keys.
Further, there is no fundamental need to create an index. You can create one if you wish, and it will speed up access to records at the cost of some additional time spent on record creation and update. See https://stackoverflow.com/a/3658980/1008891 for more discussion of this.

schema fields ordering on a rails migration

it is possible to tell rails to keep id columns at the top of the schema and timepstamps at the bottom, when adding some fields to a table through a migration?
What I want is to have always this fields in the same position when playing with rails on the console, I know it's possible to reorder them in schema.rb and reload it but I'm looking for a cleaner approach suitable for production environments too.
thank you
You can something like this (probably currently in Mysql only) from Rails 2.3.6+:
add_column :table_name, :column_name, :column_type, after: :other_column_name
or
change_table :the_table do |t|
t.column_type :column_name, after: :other_column_name
end
Sources:
- In a Rails Migration (MySQL), can you specify what position a new column should be?
- https://rails.lighthouseapp.com/projects/8994/tickets/3286-patch-add-support-for-mysql-column-positioning-to-migrations
You may be interested in the fix-db-schema-conflicts gem which automatically sorts columns alphabetically while generating the db/schema.rb file.
Timestamps would not necessarily be last in the list, but the schema will not rely on the order in which columns were added (by migrations).

How to specify order of field to add using migration in Rails 3?

How can I specify after which field I want to add a new column? (I don't want the field added in at the bottom after the timestamps)
add_column :users, :is_active, :boolean
Here is how:
add_column :users, :is_active, :boolean, :after => :some_column
where :some_column is the name of the column you want to add :is_active after.
In general, you can't and you shouldn't care. Tables in relational databases don't really have any particular order; that's why you should always specify the columns when you INSERT and never say things like select * ... (yes, ActiveRecord does that but that but that doesn't mean that it is a good idea, just because AR jumps off a cliff doesn't mean you should, etc.).
If you insist on trying to do the database's job for it then the portable way is:
Copy or rename the table to another table.
Drop the original (unless you renamed in (1)).
Create the new table with the columns in the order you want.
Hope the database pays attention to your order in (3).
Copy the data to from the table in (1) to the "new" table from (3).
...
Profit.
If you're using the MySQL or MySQL2 database adapters, you can use the :after => :some_column option to add_column. If you're using SQLite or PostgreSQL, then see the portable way above. If you're using anything else then you'll have to read the adapater's documentation or source code to see what is supported.
But you should ask yourself why you think you want to do this before proceeding.

return model with lowercase columns

I have a rails program that is accessing a legacy database with UPPERCASE table columns.
I want to be able to type user.firstname rather than user.FIRSTNAME
How do I make ActiveRecord retrieve the lowercase version of these column names to allow me to use lowercase attributes in the model?
It might be easier to change the column names with migrations. Otherwise you will have to change the gems that you are using and then pack them in vendor/gems to keep as they degrade.
script/generate migration down_case_table_names_and_columns
write the migration
rake db:migrate
For each table:
rename_table :OLD_NAME, :new_name
For each column:
rename_column :COLUMN_NAME, :column_name
problems
You might not have to change the name of the tables, fyi - you might get an error about changing the table names. I have never changed a table name so I don't know if this will work. In therms of changing column names there will be no problem.
This is probably the best way to deal with this if changing column names isn't feasible: https://github.com/reidmix/legacy_mappings

Resources