Rails: rename globalize column - ruby-on-rails

The rails globalize gem docs are great, but I can't find a solution, what I have to do, when I want to rename a column.
Last Year I did that, to add the translation fields.
def up
remove_column :news, :name
News.add_translation_fields! name: :string
end
def down
add_column :news, :name, :string, default: nil
remove_column :news_translations, :name
end
Now I want to rename the column "name" to "title", without loosing my data and translations. How do I have to write the migration file?

Alter the column on the news translations table directly:
def change
rename_column :news_translations, :name, :title
end

Related

Remove boolean and add list in ruby on rails

I would like to modify gender field,
Initially i have declared gender field as boolean true or false. but now i want it to be changed as list (Male, Female, Other).
class AddExtraFieldsToUser < ActiveRecord::Migration
def change
add_column :users, :phone_number, :string
add_column :users, :date_of_birth, :datetime
add_column :users, :gender, :boolean, default: false
add_column :users, :live_in, :string
add_column :users, :description, :text
end
end
Can i modify as following.... please let me know the correct way...
i thought of doing rails g migration RemovegenderFromUsers gender:boolean
then rake db:migrate followed by creating new one
rails g migration AddGenderToUsers gender:select
user.rb
GENDER_TYPES = ["Male", "Female", "Other"]
html
<%= f.select :gender, User::GENDER_TYPES %>
Is above mentioned process correct or any other way ?
The answer by Ahmad Hussain is correct . List is not a database field type .
You should generate a migration to change the column type :
**change_column :table_name, :column_name, :type**
Select is not a database field type if you want to do it then do it like this
rails g migration AddGenderToUsers gender:integer
In migration file change it to like this:
change_column :users, :gender, :integer, default: 0
For form page do this:
<%= f.select :gender, User::GENDER_TYPES.each_with_index.map { |gender, index| [gender, index] } %>
And in user model you can define function to get gender name to display
def gender_name
GENDER_TYPES[gender]
end

How to merge columns in a rails table?

I have a rails table of users, with columns first_name and last_name etc.
How do i merge these two together? Or how do i create a new column called name and add data from these two columns?
Basically i need a column called name which is the concatenation of the first_name and last_name.
As Richard Brown has answered, you should create a migration if you want to save the concatenated string to the database.
rails g migration add_fullname_to_users fullname
then run an sql inside the generated migration to update all records
# mysql
User.update_all('fullname = CONCAT(first_name, " ", last_name)')
# postgre
User.update_all("fullname = (first_name || ' ' || last_name)")
But I'd suggest you just keep your current setup and just create a method called fullname in your model
# user.rb
def fullname
"{first_name} #{last_name}"
end
which is better since you have access to first_name and last_name
If you want to make sure you can rollback, you can do something like this in your migration file.
def up
add_column :your_table, :name, :string
YourClass.all.each do |person|
person.update_attributes! :name => person.first_name + " " + person.last_name
end
remove_column :your_table, :first_name
remove_column :your_table, :last_name
end
And your down method for the roll back:
def down
add_column :your_table, :first_name, :string
add_column :your_table, :last_name, :string
YourClass.all.each do |person|
person.update_attributes! :first_name => person.name.match(/\w+/)[0]
person.update_attributes! :last_name => person.name.match(/\w+/)[1]
end
remove_column :your_table, :name
end
Create a migration to add the new field:
rails g migration AddNameToTableName name
You can write a rake task to do the join.
TableName.all.each do { |row| row.update_attributes(name: "#{row.first_name} #{row.last_name}") }
You can execute that from the rails console, but I like repeatable database updates so I prefer a rake task.
The \w regex matcher and concatenating with spaces as in the above examples were problematic for me, although I had the opposite problem, splitting a name into first and last names. Instead, consider using what I ended up with. Back up your databases first, and test this in development!
def up # Split name into first and last
add_column :people, :first_name, :string
add_column :people, :last_name, :string
Person.all.each do |person|
person.update_column(:first_name, person.attributes["name"].rpartition(" ").first)
person.update_column(:last_name, person.attributes["name"].rpartition(" ").last)
person.save(:validate => false)
end
remove_column :people, :name
end
def down # Merge first and last into name
add_column :people, :name, :string
Person.all.each do |person|
person.update_column(:name, [person.attributes["first_name"].to_s, person.attributes["last_name"].to_s].reject(&:blank?).join(" "))
person.save(:validate => false)
end
remove_column :people, :first_name
remove_column :people, :last_name
end
This avoids inserting stray spaces in case one of the names is nil, and also splits a fullname more effectively into first and last names; specifically, by splitting on the last space in the name, since "First Middle" "Last" is more of a human-compatible split than "First" "Middle Last". See examples:
# Before split
> puts p.name.inspect
"Prince"
"Test User"
"Jean Luc Picard"
# After split
> puts p.first_name.inspect + " " + p.last_name.inspect
"" "Prince"
"Test" "User"
"Jean Luc" "Picard"
My main complaint is that "Prince" should probably be a first name not a last name, but then again depending on your database constraints it might need to go into the last_name field anyway.
In my rails 4 app with a User model I generated my migration file
rails g migration RemoveFirstLastNameColumnsFromUser
Then I put in
class RemoveFirstLastNameColumnsFromUser < ActiveRecord::Migration
def up
add_column :users, :name, :string
User.all.each do |u|
u.update! name: "#{u.first_name} #{u.last_name}"
end
remove_column :users, :first_name
remove_column :users, :last_name
end
def down
add_column :users, :first_name, :string
add_column :users, :last_name, :string
User.all.each do |u|
n = u.name
u.update! last_name: n.slice!(/\w+\z/)
u.update! first_name: n.strip
end
remove_column :users, :name, :string
end
end
This #down method will account for names with more than one space.

Rails Globalize3 gem: How do I add an additional field to the translation table using a migration?

The docs for the Globalize3 gem are clear about how to create a translation table, but I don't see any information about how to add a field to a translation table during a later migration. For example, I initially included Category.create_translation_table! :name => :string when I created my Category model. Now, however, I need to add a translated field to the model.
How do I do that with a Rails migration? I don't see any docs for an alter_translation_table! method or anything similar...
You can do it by hand, something like the following:
class AddNewFieldToYourTable < ActiveRecord::Migration
def self.up
change_table(:your_tables) do |t|
t.string :new_field
end
change_table(:your_table_translations) do |t|
t.string :new_field
end
end
def self.down
remove_column :your_tables, :new_field
remove_column :your_table_translations, :new_field
end
end
With Globalize4, just :
class AddHintToCategory < ActiveRecord::Migration
def up
Category.add_translation_fields! hint: :text
end
def down
remove_column :category_translations, :hint
end
end
Don't forget to add the new field in your model :
translate :name, :hint
https://github.com/globalize/globalize/blob/master/lib/globalize/active_record/migration.rb:34 line (globalize 4)
add_translation_fields!(fields, options)
P.S. Just a typo in a previous comment, 'add_transaction_fields' isn't defined.

rails date_select

Right now I am saving my dates as a string in the format of mm/dd/yyyy, but want to convert to date_select but I keep getting errors for some reason.
Here is the code that I am using
the form
<%= f.date_select :start_date %>
the model
validates :start_date, :presence => true
but I get an error from my controller saying that it doesnt fit the params.
That's because of the way Rails automatically looks at a database column to figure out what type of object is going to be stored there. In this case, Rails is looking for a Datetime column to be used in conjunction with the date_select helper, but instead it's finding a varchar column.
I would run a migration to drop the start_date column, and re-add it as a datetime column, like so
To generate a new migration:
rails generate migration [name of your migration]
In your case something like:
rails generate migration change_start_date_column_to_timestamp
This will generate a file in your RAILS_ROOT/db/migrations folder, which will look something like:
class ChangeStartDateColumnToTimestamp < ActiveRecord::Migration
def self.up
end
def self.down
end
end
And you need to modify it to look like:
class ChangeStartDateColumnToTimestamp < ActiveRecord::Migration
def self.up
remove_column :table_name, :start_date
add_column :table_name, :start_date, :timestamp
end
def self.down
remove_column :table_name, :start_date
add_column :table_name, :start_date, :string
end
end
Then, when rails pulls the data from the database, it'll automatically convert them to Ruby Time objects.
A word of caution... this will destroy the data in the start_date field. So if you have pre-existing information that needs to be preserved, you need to do something more complicated.

Create a set column with database migration in rails

I need to add a new column to my users table in the database. I want the type of the column to be set. The column represents the users gender. There should be two options to the set. One form Male "m" and the other for Female "f".
But I haven't found any documentation for adding a column with the set type.
How can I do this?
What db is used? mysql? If you're want to use SET datatype, you'll have to do it manually, as rails doesn't support it. However, I'd do just
t.string :gender, :limit => 1
for the sake of convenience.
In your Users model, you should add the following line to require M/F answers.
validates_inclusion_of :gender, :in => %w( m f M F)
I think you want to add the gender column with a default datatype (correct me if I'm wrong), If so there would be the step
here I'm assuming 'M' is for male and "F" is for female (you can use integers also if you wish)
create a migration
ruby script/generate migration add_gender_column_to_users
This will create a migration for you and as the name implies it will add a gender column to your users table
in your migrations self.up action add this
add_column :users, :gender, :string, :default => 'm'
here it says we are adding a gender column of string type and its default values is 'm'
and add this to self.down events
remove_column :users, :gender
so your final migration will look something like this
class AddGenderColumnToUsers < ActiveRecord::Migration
def self.up
add_column :users, :gender, :string, :default => 'm'
end
def self.down
remove_column :users, :gender
end
end
and do a
rake db:migrate
thats it, hope this helps

Resources