Rails won't let me change records during migration - ruby-on-rails

This must be something simple but it's driving me nuts!
I have a migration where I want to update a record afterward
class SubjectsTextField < ActiveRecord::Migration
def self.up
add_column :users, :subjects, :text
User.find(39).update_attribute :subjects, "hey there"
end
def self.down
remove_column :users, :subjects
end
end
The column gets created but when I go to check record 39, it's subjects field is null and doesn't say "hey there". No errors are thrown during the migration and the update_attribute line returns true as if it had worked.
This line works perfectly in the console and has the expected effect:
User.find(39).update_attribute :subjects, "hey there"
I tried putting the update_attribute line in a second migration. If I blow through both of them in one "rake db:migrate" all the way to current, it still doesn't work.
But here is the weird part. If I run two separate migrations, say "rake db:migrate VERSION=10" to only create the column and then the second one with "rake db:migrate" to update the attribute IT WORKS!
What the heck is going on...how do I modify a record during a migration? I seem to remember doing this quite often in the past. Maybe it is something different with Rails 2.3.2?
Thanks!
Brian

You need to call reset_column_information on the model you changed before you can use the new column. Add this between the add_column and update:
User.reset_column_information
See "Using a model after changing its table" on the ActiveRecord::Migration page.

This syntax is much clear...try with change_table
class AddReceiveNewsletterToUsers < ActiveRecord::Migration
def self.up
change_table :users do |t|
add_column :users, :subjects, :text
end
User.find(39).update_attribute "subjects", "hey there"
end
def self.down
remove_column :users, :receive_newsletter
end
end

If you combine the two in your initial migration like this, does that work?
class SubjectsTextField < ActiveRecord::Migration
def self.up
add_column :users, :subjects, :text
User.find(39).update_attribute "subjects", "hey there"
end
def self.down
remove_column :users, :subjects
end
end

Related

Changing column names with paperclip gem

Is there a way to change the column names that paperclip uses when generating its database migration? For example, currently a paperclip migration looks like this:
class AddAvatarColumnsToUsers < ActiveRecord::Migration
def self.up
add_attachment :users, :avatar
end
def self.down
remove_attachment :users, :avatar
end
end
And it generates the following in the database:
avatar_file_name
avatar_file_size
avatar_content_type
avatar_updated_at
Ideally I'd like to change the avatar_file_name to correspond to a column in the database called "content". Is this possible?
Renaming columns, to something else than <attachment>_<attribute> will not work in Paperclip.
It mandatorily needs the following 4 attributes for each attachment in the model:
<attachment>_file_name
<attachment>_file_size
<attachment>_content_type
<attachment>_updated_at
Check this post out for a debate on why following a <attachment>_url approach might be better than having a separate model for attachment (<attachment>.url): Paperclip and Inheritance (STI)
For users that leverage S3 or Google Cloud Storage, you may need to move your files to a new directory following on paperclip's file naming scheme. Here is a sample migration to point you in the right direction:
class MovePaperclipAssets < ActiveRecord::Migration
def up
storage = Fog::Storage::Google.new google_storage_access_key_id: ENV["GOOGLE_ACCESS_KEY_ID"],
google_storage_secret_access_key: ENV["GOOGLE_SECRET_ACCESS_KEY"]
bucket = storage.directories.get('bucket-name')
bucket.files.each do |file|
if file.key.starts_with?("original/directory")
newfile = file.key.gsub("original/directory","new/directory")
file.copy('bucket-name', newfile)
file.destroy
end
end
end
def down
storage = Fog::Storage::Google.new google_storage_access_key_id: ENV["GOOGLE_ACCESS_KEY_ID"],
google_storage_secret_access_key: ENV["GOOGLE_SECRET_ACCESS_KEY"]
bucket = storage.directories.get('bucket-name')
bucket.files.each do |file|
if file.key.starts_with?("new/directory")
newfile = file.key.gsub("new/directory","original/directory")
file.copy('bucket-name', newfile)
file.destroy
end
end
end
end
ruby script/generate migration RenameDatabaseColumn
class RenameDatabaseColumn < ActiveRecord::Migration
def self.up
rename_column :user, :avatar_file_name, :user_file_name
rename_column :user, :avatar_file_size, :user_file_size
rename_column :user, :avatar_content_type, :user_content_type
rename_column :user, :avatar_updated_at, :user_updated_at
end
def self.down
# rename back if you need or do something else or do nothing
end
end
Just try the migration may be it will work for you. add column name whatever corresponding column name.
When you run the rails g migration add_avatar_columns_to_users, you can write as you wrote. But if you want to change the column names, go to the migration file and change them as you want as following. Please don't migrate it untill and unless you change the columns.
class AddAvatarColumnsToUsers < ActiveRecord::Migration
def self.up
add_column :users, :your_file_name,:string
add_column :users, :your_content_type, :string
add_column :users, :your_file_size,:integer
add_column :users, :yourfile_updated_at,:datetime
end
def self.down
remove_column :users, :your_file_name
remove_column :users, :your_content_type
remove_column :users, :your_file_size
remove_column :users, :yourfile_updated_at
end
end
Now run rake db:migrate
The above will work for sure. And add your attachments accordinbly.

Why is this migration irreversible? (change_table, rename, text)

I have what I think is a pretty simple migration. For some reason I get an IrreversibleMigration error when I try to db:rollback or db:migrate:redo.
The migration runs smoothly, but I'd rather keep it reversible. I can't figure out why it's not as written. Any ideas?
Here's the migration:
class AddWhyHypAndWhyHypeToStatements < ActiveRecord::Migration
def change
change_table :statements do |t|
t.rename :description, :why_hypocritical
t.text :why_hypothetical
end
end
end
If it matters, "description" column is a text column. I'm using Rails 3.1/Ruby 1.9.2/PostgreSQL. Thanks for any help.
Looks like Rails has troubles reverting change_table method. Try doing it that way instead:
class AddWhyHypAndWhyHypeToStatements < ActiveRecord::Migration
def change
rename_column :statements, :description, :why_hypocritical
add_column :statements, :why_hypothetical, :text
end
end
You can see the list of commands that can be inverted in the docs or in Rails Guides.

Undefined add_column in Rails 3

I am trying to run a migration in Rails 3, I wish to add a column to a table, the code looks like this:
class AddConstAdr < ActiveRecord::Migration
def change
change_table: constants do |t|
t.add_column :home_address, :string
end
end
end
When I do rake db:migrate I get an error saying undefined method 'add_column'. I am confused as to why this is happening, can anyone help?
You seem to be mixing two different ways of doing a migration. You probably want this:
def change
change_table :constants do |t|
t.string :home_address
end
end
or this:
def change
add_column :constants, :home_address, :string
end
Both forms should do the same thing: add a home_address string column to the constants table.
I'm also assuming that your change_table: constants is just a typo that should have been change_table :constants.
Further information may be found in the Migrations Guide.
You should do as below:
def change
add_column :constants, :home_address, :string
end

Rails migration to reference a User, how to add this foreign key?

I have a 2 Models, User and Post.
I want the Post model to have a User in it i.e. add a user_id in the Posts table.
What will my migration look like? Or do I just do this manually like:
add_column :posts, :user_id:integer
yep, just do it manually. It'll look like this:
class AddUserIDToPosts < ActiveRecord::Migration
def self.up
add_column :posts, :user_id, :integer
end
def self.down
remove_column :posts, :user_id
end
end

Alter existing model with a Redmine plugin

The Redmine plugin tutorials explain how to wrap core models but what I need is to add another column to the journals table.
I need a boolean field inserted in the journals model. Creating another model with a 'belongs_to :journal' relation seems like an overkill.
Can this be done with a plugin?
I should note that I am a rails newbie.
You just have to create the appropriate migration.
In your plugin's directory, create the file db/migrate/update_journal.rb with the following :
class UpdateJournal < ActiveRecord::Migration
def self.up
change_table :journal do |t|
t.column :my_bool, :boolean
end
end
def self.down
change_table :journal do |t|
t.remove :my_bool
end
end
end
Then you can execute the task rake db:migrate_plugins RAILS_ENV=production to update your database with the new field.
After executing the migration, your journal database will have the my_bool field that you'll be able to call like every other field.
I was able to extend the existing user model using the following code:
class UpdateUsers < ActiveRecord::Migration
def up
add_column :users, :your_new_column, :string, :default => ''
add_column :users, :your_other_new_column, :string, :default => ''
end
def down
remove_column :users, :your_new_column
remove_column :users, :your_other_new_column
end
end
Also I needed to name the migration file in way that it began with a number eg. myplugin/db/migrate/001_update_user.rb

Resources