Default value not populating in migration with Rails and Postgresql - sql

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

Related

Convert Rails migration to raw SQL

How can I convert this migration to raw sql? or Can I convert?
class AddUnsubscribeTokenToUsers < ActiveRecord::Migration
def self.up
add_column :users, :unsubscribe_token, :string, :unique => true
User.all.each do |user|
user.unsubscribe_token = ActiveSupport::SecureRandom.hex(18)
end
end
def self.down
remove_column :users, :unsubscribe_token
end
end
AFAIK you can't convert a single migration into SQL, but you can have ActiveRecord output your schema in SQL instead of Ruby.
# in config/application.rb
config.active_record.schema_format = :sql
This will give you SQL output in your db/schema instead of the Ruby DSL. But neither format will include the snippet of code setting the user token.
Also, it's considered a Bad Idea to include DB modifying code like that in your migration. For example what happens if you get rid of or rename the model, when that migration runs it will fail. At least wrap it in a check for the model. or a begin/rescue/end
if defined? User
User.all.each do |user|
user.unsubscribe_token = ActiveSupport::SecureRandom.hex(18)
end
end
or
begin
User.all.each do |user|
user.unsubscribe_token = ActiveSupport::SecureRandom.hex(18)
end
rescue
end
And lastly, that snippet is not going to do what you intended since your not saving the model after setting the token, either use update_attributes or call user.save
I stumbled upon a very nice article, describing how this can be achieved via a custom rake task.

RoR: how can I add columns to my database on my live heroku app?

I am trying to add :price, :location, and :product to the columns for my microposts table. I have already done a bunch of other migrations and I have heard that rolling back all of migrations and redoing them is error prone. So I guess the other option is the schema file? I have heard that the schema file is just to be read and not edited. I have been looking at http://guides.rubyonrails.org/migrations.html but can't find the right info. They briefly talk about change_table which I think could be useful but it doesn't go into depth. Is this what I am looking for?
Just create a new standalone migration:
rails g migration add_price_location_and_product_to_microposts
It will create a file in the db/migrate folder, edit it:
def change
add_column :microposts, :price, :float # dont forget to change the type to the columns
add_column :microposts, :location, :string
add_column :microposts, :product, :integer
end
(You can define the change method, instead of up and down because add_column is a reversible command.)
And then, run rake db:migrate

how to set default value to column in rails while creating migration

I am new to Model in rails. I know how to create model & how to add column to them. Now I want to set default value to a column but I am not getting that how exactly I can do it.
I generated new model
rails g model User
then added column to it
rails generate migration AddNotificationEmailToUsers notification_email:boolean
Now I want to set value of Notification column default as true.
Please guide me how to write the migration for the same. Thank you!!!
You can't do this from the command line - you'll have to edit the migration file and change the corresponding line to something like
add_column :users, :notification_email, :boolean, :default => true
Best approach here is to use change_column in your migration. It is advertised to change type but you can use it to attach a default to existing column.
I had
location :integer
in schema and I wanted to default to zero, so I wrote a migration as such:
change_column :player_states, :location, :integer, :default => 0
That did the trick.
Frederick Cheung is correct you will need to edit the migration file for this.
Just a minor update add comma after the data type before specifying the default value.
add_column :users, :notification_email, :boolean, :default => true
As of now there is no way around to specify default value defined through terminal in rails migration.
you can execute below steps in order to specify default value for a column
1). Execute
$ rails generate migration AddNotificationEmailToUsers notification_email:boolean
2). Specify the new column default value to TRUE/FALSE by editing the new migration file created.
class AddNotificationEmailToUsers < ActiveRecord::Migration
def change
add_column :users, :notification_email, :boolean, default: true
end
end
3).Run above generated migration by Executing.
$ rake db:migrate

rails3 migration to add new column does not save values to table

So, I created the following migration:
class AddAclToUsers < ActiveRecord::Migration
def self.up
add_column :users, :acl, :integer
end
def self.down
remove_column :users, :acl
end
end
however, after modifying the various erb files in the view, values entered in edit.html.erb are not saved to the database.
I can manually start SQlite3 and select * the table and see that the column was created but no values are entered. I can also manually UPDATE or INSERT numbers into the new column which the controller queries and displays correctly.
Any suggestions on what may be wrong with the frameworks udate/save??
-daniel
Please check if there is a list of attr_accessible in your User model. If you are using Devise like gem/plugin for authentication you would have a list of attr_accessible in the model.
Add new attribute (acl in your case) to the attr_accessible list.
If this is not the case, I would like you to paste your view, controller and model code

Adding a column to an existing table in a Rails migration

I have a Users model which needs an :email column (I forgot to add that column during the initial scaffold).
I opened the migration file and added t.string :email, did rake db:migrate, and got a NoMethodError. Then I added the line
add_column :users, :email, :string
again rake db:migrate, again NoMethodError. Am I missing a step here?
Edit: here's the migration file.
class CreateUsers < ActiveRecord::Migration
def self.up
add_column :users, :email, :string
create_table :users do |t|
t.string :username
t.string :email
t.string :crypted_password
t.string :password_salt
t.string :persistence_token
t.timestamps
end
end
def self.down
drop_table :users
end
end
If you have already run your original migration (before editing it), then you need to generate a new migration (rails generate migration add_email_to_users email:string will do the trick).
It will create a migration file containing line:
add_column :users, email, string
Then do a rake db:migrate and it'll run the new migration, creating the new column.
If you have not yet run the original migration you can just edit it, like you're trying to do. Your migration code is almost perfect: you just need to remove the add_column line completely (that code is trying to add a column to a table, before the table has been created, and your table creation code has already been updated to include a t.string :email anyway).
Use this command on the terminal:
rails generate migration add_fieldname_to_tablename fieldname:string
and
rake db:migrate
to run this migration
Sometimes rails generate migration add_email_to_users email:string produces a migration like this
class AddEmailToUsers < ActiveRecord::Migration[5.0]
def change
end
end
In that case you have to manually an add_column to change:
class AddEmailToUsers < ActiveRecord::Migration[5.0]
def change
add_column :users, :email, :string
end
end
And then run rake db:migrate
You can also do
rake db:rollback
if you have not added any data to the tables.Then edit the migration file by adding the email column to it and then call
rake db:migrate
This will work if you have rails 3.1 onwards installed in your system.
Much simpler way of doing it is change let the change in migration file be as it is.
use
$rake db:migrate:redo
This will roll back the last migration and migrate it again.
To add a column I just had to follow these steps :
rails generate migration add_fieldname_to_tablename fieldname:string
Alternative
rails generate migration addFieldnameToTablename
Once the migration is generated, then edit the migration and define all the attributes you want that column added to have.
Note: Table names in Rails are always plural (to match DB conventions). Example using one of the steps mentioned previously-
rails generate migration addEmailToUsers
rake db:migrate
Or
You can change the schema in from db/schema.rb, Add the columns you want in the SQL query.
Run this command: rake db:schema:load
Warning/Note
Bear in mind that, running rake db:schema:load automatically wipes all data in your tables.
You can also add column to a specific position using before column or after column like:
rails generate migration add_dob_to_customer dob:date
The migration file will generate the following code except after: :email. you need to add after: :email or before: :email
class AddDobToCustomer < ActiveRecord::Migration[5.2]
def change
add_column :customers, :dob, :date, after: :email
end
end
You also can use special change_table method in the migration for adding new columns:
change_table(:users) do |t|
t.column :email, :string
end
When I've done this, rather than fiddling the original migration, I create a new one with just the add column in the up section and a drop column in the down section.
You can change the original and rerun it if you migrate down between, but in this case I think that's made a migration that won't work properly.
As currently posted, you're adding the column and then creating the table.
If you change the order it might work. Or, as you're modifying an existing migration, just add it to the create table instead of doing a separate add column.
You can also do this ..
rails g migration add_column_to_users email:string
then rake db:migrate
also add :email attribute in your user controller ;
for more detail check out http://guides.rubyonrails.org/active_record_migrations.html
You can also force to table columns in table using force: true, if you table is already exist.
example:
ActiveRecord::Schema.define(version: 20080906171750) do
create_table "authors", force: true do |t|
t.string "name"
t.datetime "created_at"
t.datetime "updated_at"
end
end
You could rollback the last migration by
rake db:rollback STEP=1
or rollback this specific migration by
rake db:migrate:down VERSION=<YYYYMMDDHHMMSS>
and edit the file, then run rake db:mirgate again.