How do you set a default value in a decimal column in Rails? I've tried both the following, using Rails 3 and Postgresql, but after each one the console tells me the default values are still nil. If I set the value from the console, there's no problem, but it doesn't seem to work in the migration.
#Attempt 1
add_column :providers, :commission, :decimal, :precision=>6,:scale=>4,:default=>0.1
and
#Attempt 2
add_column :providers, :commission, :decimal, :precision=>6,:scale=>4,:default=>BigDecimal("0.1")
Many thanks for your help!
It turns out I also need to set :null=>false
The following code worked:
add_column :providers, :commission, :decimal, :precision=>6,:scale=>4,:default=>0.1, :null => false
Related
I know I can do this in a change migration and have it be reversible:
add_column :widgets, :color, :string
remove_column :widgets, :flavor, :string
But strangely, change_table->remove does not work like this. Instead of params (name, type), it takes a list of column names. (If you attempt to append a type parameter, it gets interpreted as a column name.)
change_table(:widgets) do |t|
t.column :color, :string
t.remove :flavor, :string # <-- nope! It tries to remove a column named "string"
end
When you try that, you get this error:
remove_columns is only reversible if given a type.
Is there another call I am be overlooking? It seems weird that change_table could be missing such a fundamental use case, but I don't see any calls in the docs that can do it.
While experimenting, I tried this and it works:
change_table(:widgets) do |t|
t.column :color, :string
t.remove :flavor, type: :string
#^^^^^
end
So I guess that's the answer.
ActiveRecord::ConnectionAdapters::Table is generally just a thin wrapper around ActiveRecord::ConnectionAdapters::SchemaStatements - in this case remove_columns which takes a list of columns and an options hash.
type and other column options can be passed to make migration reversible.
remove_columns(:suppliers, :qualification, :experience, type: :string, null: false)
remove really just provides the first argument - which is the table.
I'm trying to add a new column, 'latitude', to an existing Postgres table, after the 'location' column.
Using this syntax puts the column in the correct place:
add_column :table, :column, :decimal, :after => :existing_column
And using this syntax ensures that the field is the correct data type
add_column :table, :column, :decimal, {:precision => 10, :scale => 6}
But when I try and combine the two:
add_column :table, :column, :decimal, {:precision => 10, :scale => 6}, :after => :existing_column
I get "ArgumentError: wrong number of arguments (5 for 3..4)"
"Not to worry", I thought, "I'll just combine the arguements!":
add_column :table, :column, :decimal, {:precision => 10, :scale => 6, :after => :existing_column}
But then the columns appear at the end of the table. What am I doing wrong?
Thanks :)
Your last definition is correct. But the problem here isn't with Rails, but with PostgreSQL, which doesn't allow to add a column at specific position. Read more: How can I specify the position for a new column in PostgreSQL?
In this SO article I can see how to add a default value to a certain table:
Add a default value to a column through a migration
change_column :shops, :currency_id, :integer, :default => 1
I have another table currencies that has an ID and also a ISO_Name. I want the system to use EUR as default value. But it's possible that this has ID 5 or ID 1 or ...
So my question: How can I define a default value that is based on the result of a query? For example Currency.find_by_iso_code('EUR').id
As you have iso_name field in the currencies, you can achieve it by the following code.
change_column :shops, :currency_id, :integer, :default => Currency.find_by_iso_name('EUR').id
How about:
class SetDefaultCurrencyForShops < ActiveRecord::Migration
def up
currency = Currency.find_by_iso_code('EUR')
if currency
change_column :shops, :currency_id, :integer, :default => currency.id
end
end
end
This seems to have been asked before: rails decimal precision and scale
But when running a change_column migration for :precision or :scale they don't actually affect the schema or database, but db:migrate runs without errors.
My migration file looks like this:
class ChangePrecisionAndScaleOfPaybackPeriodInTags < ActiveRecord::Migration
def self.up
change_column :tags, :payback_period, :decimal, { :scale => 3, :precision => 10 }
end
def self.down
change_column :tags, :payback_period, :decimal
end
end
But my schema (and the data) remains as:
t.decimal "payback_period"
Anybody else have this issue?
Thanks,
Josh
Had a related (but not same) problem. I was just changing scale, so when changing the :scale you need the full line:
change_column :something, :weight, :decimal, :precision => 10, :scale => 2
omitting :decimal (which it already was) and :precision (which already was 10) will cause the migration to fail.
Does Not Work for SQLite3
For this simple test app that I'm running I have SQLite3 setup. Apparently, SQLite3 doesn't rely on column type declarations and is more dynamic, looking at the column's content instead - as was stumbled upon here:
Modify a Column's Type in sqlite3
I haven't tested it but I'm sure that's why the schema wasn't being changed, because change_column doesn't translate to anything in SQLite3.
Thanks for the replies guys.
Delete and regenerate db\schema.rb file.
rake db:schema:dump
A hack, but it should get you where you need to go:
class ChangePrecisionAndScaleOfPaybackPeriodInTags < ActiveRecord::Migration
def self.up
execute "ALTER TABLE tags CHANGE payback_period DECIMAL(3,10)"
end
def self.down
change_column :tags, :payback_period, :decimal
end
end
I have the problem, that I have an migration in Rails that sets up a default setting for a column, like this example:
def self.up
add_column :column_name, :bought_at, :datetime, :default => Time.now
end
Suppose, I like to drop that default settings in a later migration, how do I do that with using rails migrations?
My current workaround is the execution of a custom sql command in the rails migration, like this:
def self.up
execute 'alter table column_name alter bought_at drop default'
end
But I don't like this approach, because I am now dependent on how the underlying database is interpreting this command. In case of a change of the database this query perhaps might not work anymore and the migration would be broken. So, is there a way to express the undo of a default setting for a column in rails?
Rails 5+
def change
change_column_default( :table_name, :column_name, from: nil, to: false )
end
Rails 3 and Rails 4
def up
change_column_default( :table_name, :column_name, nil )
end
def down
change_column_default( :table_name, :column_name, false )
end
Sounds like you're doing the right thing with your 'execute', as the docs point out:
change_column_default(table_name, column_name, default)
Sets a new default value for a column.
If you want to set the default value
to NULL, you are out of luck. You need
to DatabaseStatements#execute the
appropriate SQL statement yourself.
Examples
change_column_default(:suppliers, :qualification, 'new')
change_column_default(:accounts, :authorized, 1)
The following snippet I use to make NULL columns NOT NULL, but skip DEFAULT at schema level:
def self.up
change_column :table, :column, :string, :null => false, :default => ""
change_column_default(:table, :column, nil)
end
Rails 4
change_column :courses, :name, :string, limit: 100, null: false