I have a table 'users' with column 'email'. It used to be unique (with index), but a new requirement is to allow nils there.
Is there a better solution than:
remove_index :users, :email
add_index :users, :email
?
Initially it was added with option unique:
add_index :users, :email, :unique => true
I would say that you have the correct solution there as the index will need to be regenerated, hence why there is no update_index.
Hey here is a migration I just wrote up that works pretty well. I have a table 'scraped_episodes' with a column that is varchar(255) 'enclosureUrl'. I need to make this longer to long urls so this is what I used (Rails 3.2.13)
class ExpandEnclosureUrl < ActiveRecord::Migration
def up
# remove index cuz we need to
remove_index :scraped_episodes, :enclosureUrl
# change length to 2048 characters
change_column :scraped_episodes, :enclosureUrl, :text, :limit=>2048
# redo this index to only index the first 255 chars
add_index :scraped_episodes, :enclosureUrl, :length => 255
end
def down
# remove index cuz we need to
remove_index :scraped_episodes, :enclosureUrl
# use the same settings at when i first created this field
change_column :scraped_episodes, :enclosureUrl, :string, :limit=>nil
# use the same settings as when i first added this index
add_index :scraped_episodes, :enclosureUrl
end
end
Related
Is it possible to use the annotate (2.4.1.beta) gem to output globalize3 (0.2.0) translated properties in the models that they translate?
If I have a Post creation migration generated like so
class CreatePosts < ActiveRecord::Migration
def up
create_table :posts do |t|
t.timestamps
end
Post.create_translation_table! title: :string, text: :text
end
def down
drop_table :posts
Post.drop_translation_table!
end
end
and its corresponding class looking like
class Post < ActiveRecord::Base
attr_accessible :title, :text
translates :title, :text
end
since the :title and :text attributes are not in the posts table but in the post_translations table, when I run
$ annotate --position before
they are not included in the output for the Post model:
# == Schema Information
#
# Table name: posts
#
# id :integer not null, primary key
# created_at :datetime not null
# updated_at :datetime not null
#
class Post < ActiveRecord::Base
...
Is there any way to include these attributes without manually typing them in after every annotation generation?
For now, unfortunately the answer to this question is no, there is no way to include Globalize translation attributes in an annotation generation. Will just need to keep monitoring development on annotate's Github repo.
I am having an issue with Heroku in regards to adding an integer column to an existing table.
Here is how I setup my migration file:
class AddFieldsToNetwork < ActiveRecord::Migration
def self.up
add_column :networks, :phone, :integer, :limit => 10
add_column :networks, :contact, :string
end
def self.down
remove_column :networks, :phone
remove_column :networks, :contact
end
end
Now this works locally, but when I push to Heroku, I get what most people get:
!!! Caught Server Exception
HTTP CODE: 500
Taps Server Error: PGError: ERROR: integer out of range
If I change :integer to :string, then adding the columns works and functions great on Heroku. If I leave it under :integer, the :network model crashes when I create new "network".
Can anyone tell me what I might be doing wrong?
:limit - Requests a maximum column length. This is number of characters for :string and :text columns and number of bytes for :binary and :integer columns.
For phone you definitely use strings, reason is you mean 10 characters. Not bytes for numbers
What is the best way to define a fixed-length SQL column (CHAR(12) for instance) through a Rails migration ?
Why this should not handled by the model is because of the performance of char() vs varchar(), and I'd like to avoid injecting raw SQL in the database.
Edit : I know the :limit modifier, however the field is still varchar (which is bad for performance) and does not allow a minimum size.
If Rails doesn’t understand the column type, it’ll pass it straight through to the database. So if you want a char instead of varchar, just replace:
t.column :token, :string
With:
t.column :token, "char(12)"
Of course, this may or may not make your migrations non-portable to another database.
(credit to http://laurelfan.com/2010/1/26/special-mysql-types-in-rails-migrations)
def self.up
add_column("admin_users", "username", :string, :limit => 25)
end
def self.down
remove_column("admin_users", "username")
end
You can use string type with limit option in your migration file like this:
t.string :name, :limit => 12, :null => false
For a database specific type, we can now use:
t.column(:column_name, 'char(12)')
And for a complete example:
class Foo < ActiveRecord::Migration
def change
create_table :foo do |t|
t.column(:column_name, 'custom_type')
t.timestamps
end
end
end
I am currently trying to run this migration:
class AddDroppedProjectsCountToUser < ActiveRecord::Migration
def self.up
add_column :users, :dropped_projects, :integer, {:default=>0, :required=>true}
end
def self.down
remove_column :users, :dropped_projects
end
end
The column is added correctly, but none of the old records are populated with 0. They are nil. I have tried using default=>'0' as well, to no avail. Any idea why this might be happening? (Rails 3.0.3)
Edited to add: When I create a new user it works fine, and everything looks correct. It's just the old users that still have nil for that value in the table.
What happens if you say:
def self.up
add_column :users, :dropped_projects, :integer, :null => false, :default => 0
end
instead? Without the :null=>false you're still allowing NULL in dropped_projects so there's no reason for PostgreSQL to make them 0. Also, I don't think :required is a valid option for add_column; since the options are just a simple Hash and add_column only looks for options it knows about, your stray :required option is silently ignored.
you could do this:
(taken from http://apidock.com/rails/ActiveRecord/Migration)
Using a model after changing its table
Sometimes you’ll want to add a column in a migration and populate it
immediately after. In that case, you’ll need to make a call to
Base#reset_column_information in order to ensure that the model has
the latest column data from after the new column was added. Example:
class AddPeopleSalary < ActiveRecord::Migration
def up
add_column :people, :salary, :integer
Person.reset_column_information
Person.all.each do |p|
p.update_column :salary, SalaryCalculator.compute(p)
end
end
end
I believe this is due to the fact that you are changing the old migration, instead of creating a new.
In this case, the solution is to check the schema file (schema.rb). It does not change automatically, and add
t.integer "dropped_projects", default: 0, null: false
class CreateScrapes < ActiveRecord::Migration
def self.up
create_table :scrapes do |t|
t.text :saved_characters
t.text :sanitized_characters
t.string :href
t.timestamps
end
end
def self.down
drop_table :scrapes
end
end
I'm about to rake db:migrate and I'm think about the attribute type if I should be using text or string. Since saved_characters and sanitized_characters will be arrays with thousands of unicode values, its basically comma delimited data, I'm not sure if `:text' is really the right way to go here. What would you do?
Assuming you're on MySQL, the real difference between :string and :text is length. Rails uses the varchar column type for :string columns, and sets a 255 character limit on :string columns. :text, usuprisingly, uses the text column.
To me, this suggests that :string would be a really bad choice for your columns, as they are likely to exceed 255 characters.
:string is only 255 characters. you probably want :text since you mention thousands.