how to add a column to my table Users.
because I ran the migration, I have to do something like:
rails generate migration AddShowmsgColumnToUsers show_msg:boolean
and then:
rake db:migrate
but I'm not sure about "AddShowmsgColumnToUsers". how can I know how it suppose to be? why not: AddShow_msgColumnToUsers? if the problem was pluralization and singularization, I can run the rails console and check that, but how can I know about the uppercase letter: ShowMsg/Show_msg/Show_Msg/Showmsg? is there a command that helps me to check it?
In answer to your first question, it doesn't matter, as long as the table name is correct - Rails uses the arguments you specify for the columns rather than the name of the migration.
Also, you should only really be asking one question at a time... ;-)
If you generate a migration to add an column, you should use either camelcase or underscores. Besides you dont have to put "Column" inside your migration generator, with Add...To... the migration already knows you are adding a column.
So either:
rails generate migration AddShowMsgToUsers show_msg:boolean
or:
rails generate migration add_show_msg_to_users show_msg:boolean
Is the way to go. The migration-generator will result in the following migration:
class AddShowMsgToUsers < ActiveRecord::Migration
def change
add_column :users, :show_msg, :boolean
end
end
Of course you could also do it all manually, but the whole point of generators is that you don't need to write everything yourself.
Related
I have a rails app in which we were accidentally counting promotional codes twice instead of once. I was able to solve the problem in the actual codebase such that it won't happen again, but i'm having a hard time writing a migration to reset all of the old ones. I don't have a whole lot of experience with writing migrations, let alone altering them, so I decided to just adding one element to each of them first as practice, and then going forward at dividing everything in half.
With my migration I have written. the promo_codes is the name of the table, and the times_used is what I eventually want to cut in half.
class PromoCodeTest1 < ActiveRecord::Migration
def change
change_column :promo_codes, update_attribute(:times_used + 1)
end
end
Going down this road I end up getting an undefined error with update attribute. Would anybody know what I need to do to achieve this goal?
I have never seen update_attribute helper in migrations.
You need just to run SQL query (note - don't use ActiveRecord models, please).
It can look like:
def up
execute "UPDATE promo_codes SET times_used = times_used / 2;"
end
Maybe you need add some checks if columnd times_used can contain NULL values or there are odd values...
I found a problem in one of legacy applications (outdated rails-3.0.20).
This application has lots of components and nested models. Problem existed only on one of production servers (same environments like other productions and mine dev).
There was model with name space which looks like
module Great
class Item
end
end
Table name was named great_items.
When i debug/open it on server with fault i've found that calculated table name was items istead of great_items.
$ Great::Item.all
#=> ActiveRecord::StatementInvalid: No attribute named `name` exists for table `items`
So i thought mby there is simmilar class with same namespace, I've checked it and it wasn't. My 2nd thought was to set table name explicit i tried
self.table_name = 'great_items'
# &
set_table_name 'great_items'
After this changes i run rails c and table name was setted fine:
$ Great::Item.table_name
#=> 'great_items'
But when i tried to obtain some items there was a freak error, which i could not understand till now!
$ Great::Item.all
#=> ActiveRecord::StatementInvalid: Mysql2::Error: Table 'db.items' doesn't exist: SELECT `great_items`.* FROM `items` WHERE `great_items`.`some_default_scope` = 0
As you can see in above example table has correct name for select values and in where statement, but in from value is incorrect.
I was curious so I've checked ActiveRecord::Base mysql adapter and there was some kind of catching table name so i tried to reset_table_name. Reset helped to setup expected name('great_items') but above errors didn't missed.
Problem dissapeared when i turn of class catching in production enviroment - but it wasn't solution.
Finally I kinda 'solved' this using reset_column_information after set_table_name, but i think it isn't good solution either.
My question is do you know what really could cause this issue and how to solve it without reloading class cache?
Assumed table names dont take into account the modules, as you noticed.
But as you already know, you can set it yourself, using:
self.table_name = 'great_items'
According to this doc, because you use 3.0.x, you have to use:
set_table_name "great_items"
This must be put on top of your class definition
Try this
class RenameOldTableToNewTable< ActiveRecord::Migration
def self.up
rename_table :old_table_name, :new_table_name
end
def self.down
rename_table :new_table_name, :old_table_name
end
end
For the reason, I've used mysql cmd insert into table_name (....) update custom_reports ...and hence I miss out on Model validations
validates_uniqueness_of :name
validates_presence_of :name, :description
How to validate now in rails way? Or, use the mysql way to validate(needs help in this way too)?
Rails validation and other ActiveRecord and ActiveModel magic don't work if you only execute custom SQL command. None of your model classes is even instantized then.
For Mysql (or any sql like DB), you can modify the column attribute to:
Unique (this would validate uniqueness)
Not null (this would validate presence)
I know doing the above with OCI8 and oracle would result in exceptions which I am guessing should be same with ActiveRecord and Mysql, so you should be handling your exceptions correctly
But as #Marek as said you should be relying on Active record and be doing things like
Model.create()
OR
model_instance.save()
If you want to find (and perhaps handle) the entries in your db that are not valid, try the following in the rails console:
ModelName.find_each do |item|
unless item.valid?
puts "Item ##{item.id} is invalid"
# code to fix the problem...
end
end
valid? runs the Validations again, but does not alter the data.
So I've got a ruby on rails code which use float a lot (lots of "to_f"). It uses a database with some numbers also stored as "float" type.
I would like to migrate this code and the database to decimal only. Is it as simple as migrating the database columns to decimal (adding a decimal column, copying float column to decimal one, deleting float column, renaming decimal column to old float column name), and replacing "to_f" with "to_d" in the code? Or do I need to do more than that?
Thanks a lot everyone
Raphael
You can easily use a migration to do this, and Rails will generate some of the code for you.
From your command prompt, create a new migration:
rails generate migration change_price_column_to_decimal
Rails will create the migration in the directory db/migrate. The filename will be a timestamp followed by _change_price_column_to_decimal.rb.
In the generated migration, you'll add up and down methods to convert the field:
class ChangePriceColumnToDecimal < ActiveRecord::Migration
def up
change_column :products, :price, :decimal, :precision => 15, :scale => 2, null: false
end
def down
# Either change the column back, or mark it as irreversible with:
raise ActiveRecord::IrreversibleMigration
end
end
To perform the migration, run the appropriate rake task from your command prompt:
rake db:migrate
This will convert the database for you. Keep in mind that when converting from float to decimal you will lose some significant digits, depending on what you set scale to, though if you're dealing with prices of products, this probably isn't going to be much of an issue.
This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
Alias for column names in Rails
I'm writing a module of ActiveRecord models to access a MySQL legacy database. My problem is that the database has a column naming convention that looks like this: groupID, metaGroupName, flagName. Is there an easy way to make the models play nice with this naming convention?
Update:
I'd like to avoid the alias_attribute method if possible. It's not a small database, and that would be a lot of columns to alias. Is there a method in ActiveRecord that interprets column names that I can override, perhaps?
You don't want to keep repeating yourself—that's good. Fortunately, Ruby makes it rather easy. Try something like the following:
class Model < ActiveRecord::Base
column_names.each do |cn|
alias_attribute cn.underscore.intern, cn
end
end
I'd then factor that out into a Module maybe like so:
module AliasLegacyColumns
extend ActiveSupport::Concern
included do
column_names.each {|cn|
alias_attribute cn.underscore.intern, cn
}
end
end
Then just include that in your models as necessary. For further refinement I would provide an alias_columns class-level method that accepts parameters such as :include or :exclude so you can monkey-patch ActiveRecord::Base with said module but only call alias_columns as needed per model.
Just add the following to your model
alias_attribute :new_column_name, :myLegacyColumnName