rails migration copy and remove table - ruby-on-rails

I have user model and user model has_one profile model.
Also I have user.phone and user.profile.phone but I want to remove user.phone and I will use only user.profile.phone.
Before I remove the user.phone,I wanna copy user.phone to user.profile.phone if user.phone is not blank.Then I will remove user.phone
For instance:
user.phone = 123
user.profile.phone = 234
After migration:
user.phone will be removed
user.profile.phone = 123 - 234
What is the appropriate migration for this purpose?

try this
class YourMigration < ActiveRecord::Migration
def self.up
User.find_each do |user|
user.profile.update_attributes(:phone => user.phone) unless user.phone.blank?
end
remove_column :users, :phone
end
def self.down
add_column :users, :phone, :string
end
end

If your database is not very large you can simply do like this:
User.includes(:profile).all.each{ |u| u.profile.phone = u.phone unless u.phone.nil? }
in your console. Or you can write smth like this in your migration:
def change
User.includes(:profile).all.each{ |u| u.profile.phone = u.phone unless u.phone.nil? }
remove_column :users, :phone
end

class YourMigration < ActiveRecord::Migration
def self.up
User.where("phone IS NOT NULL").includes(:profiles).each{ |u| u.profile.phone = u.phone}
remove_column :users, :phone
end
def self.down
add_column :users, :phone, :string
end
end

I prefer not to use Model in migration because it creates unnecessary pain:
Assume many people working on same project and you use model in migration do commit. Other person delete the user model or applies some validation on model and dos the commit. When he or other tries to run the migrations, it may fail because the model you used is not exists or some validation.
So I recommend to use SQL statements in migration.
class SomeMigartion < ActiveRecord::Migration
def self.up
execute('update profiles p inner join users u on p.user_id = u.id set p.phone = u.phone where u.phone is not null')
remove_column :users, :phone
end
def self.down
add_coulmn :users, :phone
end
end

Related

Combine columns in a rails migration

I'm writing an ActiveRecord migration to split a single name attribute into first and last names. I think the schema-altering part below is correct, but can I use the migration to transfer existing data as well?
The reversion case is pretty simple- we'd combine the contents of first_name & last_name, separated by a space. For the splitting, we could split name on the first instance of whitespace and save the halves to first_name & last_name. (I know this is a shaky assumption and that names are fussy- but it will take care of most cases, and the remainder can be fixed manually).
class BreakUpNameColumnInAddressBook < ActiveRecord::Migration
def up
add_column :shipping_addresses, :first_name, :string
add_column :shipping_addresses, :last_name, :string
remove_column :shipping_addresses, :name
end
def down
add_column :shipping_addresses, :name, :string
remove_column :shipping_addresses, :first_name
remove_column :shipping_addresses, :last_name
end
end
You can run any code you like in a migration so just do what you need to do (untested, be careful):
class BreakUpNameColumnInAddressBook < ActiveRecord::Migration
def up
add_column :shipping_addresses, :first_name, :string
add_column :shipping_addresses, :last_name, :string
ShippingAddress.all.each do |address|
fn, ln = address.name.split(' ', 2)
address.update(first_name: fn, last_name: ln)
end
remove_column :shipping_addresses, :name
end
def down
add_column :shipping_addresses, :name, :string
ShippingAddress.all.each do |address|
n = [address.first_name, address.last_name].join(' ')
address.update(name: n)
end
remove_column :shipping_addresses, :first_name
remove_column :shipping_addresses, :last_name
end
end
Split method splits the string into (at most) two chunks after the first occurrence of whitespace. Join method merges the elements of the array putting the space in between them.

How to migrate with data update on *one time* joined columns?

I'm adding a new association to existing models with existing data in a Rails 3.2.x + AR project.
The Migration script:
class AddUserToSignups < ActiveRecord::Migration
def up
add_column :signups, :user_id, :integer, :default => nil
add_index :signups, :user_id
# UPDATE SIGNUPS S JOIN USERS U ON S.EMAIL=U.EMAIL SET S.USER_ID = U.ID
end
def down
drop_column :signups, :user_id
end
end
How do I do a joined update per the comment above with AR? I come from a Sequel ORM background, so Sequel's approach would be:
DB[:signups___s].join(:users___u, :u__id => :s__user_id).update(:s__user_id => :u__id)
def up
add_column :signups, :user_id, :integer, :default => nil
add_index :signups, :user_id
ActiveRecord::Base.connection.execute("UPDATE SIGNUPS S JOIN USERS U ON S.EMAIL=U.EMAIL SET S.USER_ID = U.ID")
end

How can I add index, and reindex to the existing attribute?

I'm fetching a record by the code just like these
#community = Community.find_by_community_name(params[:community_name])
#user = User.find_by_username(params[:username])
I want to make it faster loading, so I'm thinking of adding index to them just like this.
If I do rake db:migrate, does it reindex to the existing records also?
Or just the records that will be created from now on?
Do it improve the speed of loading by adding index just like this?
class AddIndexToCommunity < ActiveRecord::Migration
def self.up
add_index :communities, [:community_name, :title, :body], :name=>:communities_idx
end
def self.down
remove_index :communities, [:community_name, :title, :body], :name=>:communities_idx
end
end
class AddIndexToUser < ActiveRecord::Migration
def self.up
add_index :users, [:username, :nickname, :body], :name=>:users_idx
end
def self.down
remove_index :users, [:username, :nickname, :body], :name=>:users_idx
end
end
rake db:migrate will perform database migrations and apply indeces immediately.You should apply indeces only to columns which you use in searching. Remember that indeces add time penalty on insert and update operations. If you load records on by their names, add indeces only to names:
class AddIndexToCommunity < ActiveRecord::Migration
def self.up
add_index :communities, :community_name
end
def self.down
remove_index :communities, :community_name
end
end
class AddIndexToUser < ActiveRecord::Migration
def self.up
add_index :users, :username
end
def self.down
remove_index :users, :username
end
end

Active Record query

I have two models ForumThread and Post set-up like this:
class ForumThread < ActiveRecord::Cached
has_many :posts
end
class Post < ActiveRecord::Cached
end
class CreateForumThreads < ActiveRecord::Migration
def self.up
create_table :forum_threads do |t|
t.column :thread_name, :text
end
add_index :forum_threads, :thread_name
end
def self.down
drop_table :forum_threads
end
end
class CreatePosts < ActiveRecord::Migration
def self.up
create_table :posts do |t|
t.column :post_body, :text
t.integer :forum_thread_id, :null => false
t.integer :priority
end
end
def self.down
drop_table :posts
end
end
I'd like to create a query that returns all forum threads where there's at least one post in each thread with priority of one. How do I create this query?
I've been considering something like ForumThread.joins(:posts).select(:priority => 1). I'm relatively new to Active Record (and totally new to joins) so any help is appreciated.
ForumThread.joins(:posts).where(:posts => {:priority => 1})
see join with conditions
First of all you should rename thread_id field to forum_thread_id in posts table and add posts_count to forum_threads table.
In Post class add belongs_to :forum_thread, :counter_cache => true
Now you can query ForumThread.where("posts_count > ?", 1).joins(:posts).where("posts.priority = ?", 1) which will return you a collection of posts.

rails generate migration command to insert data into the table

I have a table and I had to add a migration script to add rows in the table.
Please help with the rails generate migration command to insert data into the table.
Thanks,
Ramya.
You can write regular ruby code inside a migration. So you can simply do something like this:
class Foo < ActiveRecord::Migration
def self.up
User.create(:username => "Hello", :role => "Admin")
end
def self.down
User.delete_all(:username => "Hello")
end
end
Just write regular ruby inside your migration same as you would in pry or rails console.
The code helped me is the sql statement as show
In migration file
def up
execute("insert into salary_ranges(salary_range) values('Above 2000');")
end
class AddFieldInUsers < ActiveRecord::Migration
def self.up
add_column :users, :admin, :boolean, :null => false, :default => 0
end
def self.down
remove_column :users
end
end

Resources