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.
Related
I am using ruby 1.8.7 and rails 1.2.6. (Its old I know. But I have to use it.) I need to add column to users table. I cant use rails generate migration with rails 1.2.6. I need to add a versioned db migrate file. How can I do that?
I want to add product column to users table. I created a file in the db/migrate folder with following contents.
class AddProductToUser < ActiveRecord::Migration
def self.up
add_column :users, :product, :string
end
def self.down
remove_column :users, :product
end
end
I used script/generate migration AddProductToUser. It gives an error as
undefined method 'cache' for Gem:Module.
Any pointers on how to run migration in rails 1.2.6(<2.x) will also be useful.
Your migrate file looks (almost) fine, does the filename match the class name, and does it have a sequence number at the beginning that follows on from the previous migrate?
Slight change:
# db/migrate/123_add_product_to_user.rb
class AddProductToUser < ActiveRecord::Migration
def self.up
add_column :users, :product, :string
end
def self.down
remove_column :users, :product # note sure where radius came from?
end
end
Then should just be run with rake migrate
More info at apidock
I am looking for ways to write migrations in rails that can be executed against the database many times without failing.
For instance let say I have this migration:
class AddUrlToProfile < ActiveRecord::Migration
def self.up
add_column :profile, :url, :string
end
def self.down
remove_column :profile, :url
end
end
If the url column already exists in the Profile table (if the schema.rb has been modified unexpectedly for instance), my migration will fail saying that it's a duplicate!
So how to execute this migration only if it has to?
Thanks
You can do something like this:
class AddUrlToProfile < ActiveRecord::Migration
def self.up
Profile.reset_column_information
add_column(:profile, :url, :string) unless Profile.column_names.include?('url')
end
def self.down
Profile.reset_column_information
remove_column(:profile, :url) if Profile.column_names.include?('url')
end
end
This will reset the column information before it begins - making sure that the Profile model has the up-to-date column information from the actual table. It will then only add the column if it doesn't exist. The same thing happens for the down function, but it only removes the column if it exists.
If you have multiple use cases for this you could factor the code out into a function and re-use that in your migrations.
For Rails 3.X, there's the column_exists?(:table_name, :column_name) method.
For Rails 2.X, you can check the existence of columns with the following:
columns("<table name>").index {|col| col.name == "<column name>"}
...or if you're not in a migration file:
ActiveRecord::Base.connection.columns("<table name>").index {|col| col.name == "<column name>"}
If it returns nil, no such column exists. If it returns a Fixnum, then the column does exist. Naturally, you can put more selective parameters between the {...} if you want to identify a column by more than just its name, for example:
{ |col| col.name == "foo" and col.sql_type == "tinyint(1)" and col.primary == nil }
This should work
def self.table_exists?(name)
ActiveRecord::Base.connection.tables.include?(name)
end
if table_exists?(:profile) && !Profile.column_names.include?("url")
add_column :profile, :url, :string
end
Wrapping my migration in a conditional worked for me.
Rails 4.X
class AddUrlToProfile < ActiveRecord::Migration
unless Profile.column_names.include?("url")
def self.up
add_column :profile, :url, :string
end
def self.down
remove_column :profile, :url
end
end
end
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
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
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