Rails change_column migration - ruby-on-rails

I have this inside create_table:
t.string 'email', :default => '', :null => false
And then in another migration have this:
change_column('admin_users', 'email', :string, :limit => 100)
After I run everything, in schema.rb I get this:
t.string "email", limit: 100, default: "", null: false
Wasn't change_column supposed to overwrite everything in the previous definition? Why did :default and null were left? I was watching a tutorial where it said change_column overwrites everything. Was there some recent Rails version when this was changed?

Not necessarily, change_column does not erase previously-set details. Let's say you were changing the column so you could simply add a NULL constraint. It wouldn't make sense to have to add in all the other previously-set contraints as well.
If you want to change the default or null settings, just do so in the change_column method.
change_column('admin_users', 'email', :string, :limit => 100, :default => "", :null => true)
Otherwise, to erase everything, do remove_column then add_column:
remove_column('admin_users', 'email')
add_column('admin_users', 'email', :string, :limit => 100)

change_column doesn't overwrite everything, it just makes the changes you specify. So it added the limit to the column, but that's all.

Related

Changing fields to NOT NULL with NULL fields using migrations

So I mistakenly created a table with fields which should have been NOT NULL.
I need to create a migration to change the fields from NULLABLE to NOT NULL, but some rows exist which are already NULL.
Hoe can I update these rows and change the fields? I tried this:
def change
change_column :countries, :effective_date, :date, :null => false, :default => Time.now
change_column :countries, :expiry_date, :date, :null => false, :default => Time.new(9999,12,31)
end
But this failed with an error:
Mysql2::Error: Invalid use of NULL value: ALTER TABLE
Any ideas? Needs to work on both mysql and sql server..
First ensure there are no NULLs and then change the constraint.
Option 1:
Country.where(effective_date: nil).update_all(effective_date: Time.now)
Country.where(expiry_date: nil).update_all(expiry_date: Time.new(9999,12,31))
change_column :countries, :effective_date, :date, :null => false
change_column :countries, :expiry_date, :date, :null => false
Option 2:
change_column_null :countries, :effective_date, false, Time.now
change_column_null :countries, :expiry_date, false, Time.new(9999,12,31)
You can set the default value for all NULL columns before adding the constraint, for example:
execute "UPDATE study_sites SET patients_recruited = 0 WHERE patients_recruited IS NULL"
change_column :study_sites, :patients_recruited, :integer, default: 0, null: false

Database not completely updated in rails migration

I am new to Ruby on Rails. I have a migration called create user
class CreateUsers < ActiveRecord::Migration
def change
create_table :users do |t|
t.column :username, :string, :limit => 25, :default => "", :null => false
t.column :hashed_password, :string, :limit => 40, :default => "", :null => false
t.column :first_name, :string, :limit => 25, :default => "", :null => false
t.column :last_name, :string, :limit => 40, :default => "", :null => false
t.column :email, :string, :limit => 50, :default => "", :null => false
t.column :display_name, :string, :limit => 25, :default => "", :null => false
t.column :user_level, :integer, :limit => 3, :default => 0, :null => false
end
User.create(:username=>'test',:hashed_password=>'test',:first_name=>'test',:last_name=>'test',:email=>'test#test.com',:display_name=> 'test',:user_level=>9)
end
end
When I run rake db:migrate the table is created with the columns as mentioned above but the test data are not there
mysql>select * from users;
Empty set (0.00 sec)
EDIT I just dropped the whole database and restarted the migration and now it is showing the following error.
rake aborted!
An error has occurred, all later migrations canceled:
Can't mass-assign protected attributes: username, hashed_password, first_name, last_name, email, display_name, user_level
What am I doing wrong please help?
Thank you.
add
attr_accessible :username, :hashed_password, :first_name, :last_name, :email, :display_name, :user_level
to your user.rb
That's Rails way of prohibiting users to create or update objects via a param hash. You need to specify your User attributes as attr_accessible in your model:
example :
class User
attr_accessible :username, :firstname (etc)
end
Read more about Mass Assignment here.
just to complete the answer about testing environment. You can run rake db:test:prepare to check the migrations and load schema !

Why do created_at/updated_at get created when migration does not have timestamps?

I'm using rails 3.2 with the following migration and created_at/updated_at both get generated. I was under the impression that adding t.timestamps was what caused those columns to get generated.
class CreateContactsCountries < ActiveRecord::Migration
def change
create_table :contacts_countries do |t|
t.string :name, :official_name, :null => false
t.string :alpha_2_code, :null => false, :limit => 2
t.string :alpha_3_code, :null => false, :limit => 3
end
add_index :contacts_countries, :alpha_2_code
end
end
Please delete the table and check again becuase
By default, the generated migration will include t.timestamps (which creates
the updated_at and created_at columns that are automatically populated
by Active Record).
Ref this

Rails Migration Decimal Column :default=> 0 re-setting MySQL precision to 0?

I'm using Rails 3.0.3 (don't ask) and when I run a migration for table with decimal column and set :default => 0 it's re-setting the column's scale and precision to (10,0).
def self.up
create_table :courses do |t|
t.integer :user_id
t.string :name
t.decimal :distance, :precision => 5, :scale => 2, :default => 0
t.text :notes
t.timestamps
end
end
When I remove the :default=>0 option from the migration the column's scaled and precision are correct: (5,2)
I tried running a change_column migration with only :default =>: 0 set, but the column's scale and precision were re-set to (10,0)
change_column :courses, :distance, :decimal, :default => 0.0
I know I can go into MySQL and correct the precision and scale of the column, but wondering if I'm doing something wrong or if this is a bug?
Google reveals no information so I think I'm doing something wrong.
Try this one: t.decimal :distance, :precision => 5, :scale => 2, :default => 0.00
I was also stuck on this one, and i cant find a solution to it. Eventually i had to go into mysql and change the required precision, scale and default value, i used this from here with a few modifications
mysql> ALTER TABLE question ADD (price INTEGER);
mysql> ALTER TABLE question DROP price;
mysql> ALTER TABLE question ADD (frig DECIMAL(5,2));
mysql> ALTER TABLE question CHANGE frig price DECIMAL(5,2);
mysql> ALTER TABLE question ALTER status SET DEFAULT '0';
mysql> ALTER TABLE question MODIFY price INTEGER;
Also try :default => 0.0 #note the 0.0 as the default value must be in the data type specified i.e. decimal
Hope it helps.
You can also do
def change
change_column :courses , :distance, :decimal, :precision => 5, :scale => 2, :null => false, :default => '0'
end
I am just trying this right now and seems to work.
Active Records Migrations
class ChangeVisitratioFormatInCampaigns < ActiveRecord::Migration[5.0]
def change
reversible do |dir|
change_table :campaigns do |t|
dir.up { t.change :visitratio, :decimal, :precision => 5, :scale => 4, :default => 1 }
dir.down { t.change :visitratio, :integer }
end
end
end
end

In a rails migration, how can you remove the limit of a field

Is the following correct?
change_column :tablename, :fieldname, :limit => null
If you previously specified a limit in a migration and want to just remove the limit, you can just do this:
change_column :users, :column, :string, :limit => 255
255 is the standard length for a string column, and rails will just wipe out the limit that you previously specified.
Updated:
While this works in a number of Rails versions, you would probably be better suited to use nil like in Giuseppe's answer.
change_column :users, :column, :string, :limit => nil
That means the only thing you were doing wrong was using null instead of nil.
Here's what happened to me.
I realized that a string field I had in a table was not sufficient to hold its content, so I generated a migration that contained:
def self.up
change_column :articles, :author_list, :text
end
After running the migration, however, the schema had:
create_table "articles", :force => true do |t|
t.string "title"
t.text "author_list", :limit => 255
end
Which was not OK. So then I "redid" the migration as follows:
def self.up
# careful, it's "nil", not "null"
change_column :articles, :author_list, :text, :limit => nil
end
This time, the limit was gone in schema.rb:
create_table "articles", :force => true do |t|
t.string "title"
t.text "author_list"
end
Change the column type to :text. It does not have a limit.
change_column :tablename, :fieldname, :text, :limit => nil
Strings without limit is not something most databases support: you have to specify size in varchar(SIZE) definition.
Although you could try, I would personally go with :limit => BIG_ENOUGH_NUMBER. You may also consider using CLOB type for very big texts.
To make it db-driver-independent one should write smth like this:
add_column :tablename, :fieldname_tmp, :text
Tablename.reset_column_information
Tablename.update_all("fieldname_tmp = fieldname")
remove_column :tablename, :fieldname
rename_column :tablename, :fieldname_tmp, :fieldname
I was the same boat today, trying to remove a limit I'd added to a text field and it wouldn't take. Tried several migrations.
Rails 4.2.7.1
Ruby 2.3.1p112
In the end, the only thing that worked was specifying a limit of 255. Trying to adjust to anything else wouldn't work for me.

Resources