Combine columns in a rails migration - ruby-on-rails

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.

Related

Added Column in Rails, Data isn't recorded

I have been having the same problem for a month and cannot find a solution.
Whenever I add a column to my database, the column does not record information. I can pass information into it in my form, but that will never return.
Validations return an error, as if that field of the form was empty.
I have experimented with db:rollback, drop/create/migrate, and others.
Here is my initial migration, everything works fine:
class CreateRequests < ActiveRecord::Migration[5.0]
def change
create_table :requests do |t|
t.string :library
t.string :librarian
t.string :program
t.string :email
t.string :phone
t.string :date
t.string :time
t.timestamps
end
end
end
Here are my two added migrations:
class AddAddressColumnToRequests < ActiveRecord::Migration[5.0]
def change
add_column :requests, :address, :string
end
end
and
class AddConfirmationColumnToRequests < ActiveRecord::Migration[5.0]
def change
add_column :requests, :confirmation, :boolean
end
end
This has been my bane. Let me know what else to provide.
Thank you.
Make sure you are allowing address & confirmation in the strong params. The code should look like:
private
# Using a private method to encapsulate the permissible parameters is
# a good pattern since you'll be able to reuse the same permit
# list between create and update. Also, you can specialize this method
# with per-user checking of permissible attributes.
def request_params
params.require(:request).permit(:library, :librarian, :program, :email, :phone,
:date, :time, :age, :address, :confirmation)
end

How can I change column type on rails 5

I insert a column in my sqlite with a wrong type "stringimage".
How can I change the column type to string?
I tried change_column :users, :uid, :string
and
def up
change_table :users do |t|
t.change :uid, :stringimage
end
end
def down
change_table :users do |t|
t.change :uid, :string
end
end
but it doesn't works.
I tried many things but none of it works, maybe because I'm using rails 5.
You Need to write following two definitions into your migration :
def up
change_column :my_table, :my_column, :string
end
def down
change_column :my_table, :my_column, :stringimage
end
Note that change_column is an irreversible migration. It will cause an error if you try to rollback. To prevent this, modify the usual change method in the migration to use two separate up and down methods like this:
class ChangeUsersUidType < ActiveRecord::Migration
def up
change_column :users, :uid, :string
end
def down
change_column :users, :uid, :stringimage
end
end
If you liked this answer you can read more in this article: https://kolosek.com/rails-change-database-column.
You can try this:
change_column(table_name, column_name, type, options): Changes the column to a different type using the same parameters as add_column.

Could not find table

I don`t understand why I am getting the error:
could not find table libraryusers10s
In my code below, I define two tables library_users10 and library_books10 , and associate them with classes.
The following code works fine:
require 'active_record'
ActiveRecord::Base.establish_connection(
:adapter => "sqlite3",
:database => "library8")
ActiveRecord::Schema.define do
create_table :library_users10 do |table|
table.column :user_id, :integer
table.column :name, :string
table.column :age, :string
table.column :books_borrowed, :integer
end
create_table :library_books10 do |table|
table.column :books_id, :integer
table.column :borrower_id, :integer
table.column :title, :string
table.column :borrowed, :string
table.column :due_back, :string
end
end
class LibraryUsers10 < ActiveRecord::Base
has_many :library_books9s
end
class LibraryBooks10 < ActiveRecord::Base
belongs_to :library_users10s
end
But when I try to populate the table, by adding the following code to the script, I get the error could not find table libraryusers10s
libraryusers10 = LibraryUsers10.create(:user_id => 1, :name => 'Tom', :age => 10, :books_borrowed => 3 )
libraryusers10.library_books10.create(:borrower_id => 1, :title => 'Who let the dogs out?', :borrowed => '13_November_2013', :due_back => '21_November_2013' )
Does anybody have any suggestions as to what is going wrong here?
Thanks for any help.
The Rails convention is for table names to be pluralized
create_table :library_users10s do |table|
...
create_table :library_books10s do |table|
...
would fix things up for you.
If you cannot do that, then you can add a modifier to your models to skip the inflector like this:
class LibraryUsers10 < ActiveRecord::Base
self.table_name = 'library_users10'
...
What i can guess is because of the 'S' at the end of the Class..For example:
Person.all queries the persons table.
I guess if you add a 's' when you create your tables it should work.
create_table :library_users10s
and
create_table :library_books10s
It should work.

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

rails migration copy and remove table

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

Resources