aboutsummaryrefslogtreecommitdiffstats
path: root/activerecord
diff options
context:
space:
mode:
Diffstat (limited to 'activerecord')
-rw-r--r--activerecord/CHANGELOG.md18
-rw-r--r--activerecord/lib/active_record/attribute_methods/read.rb4
-rw-r--r--activerecord/lib/active_record/connection_adapters/abstract_mysql_adapter.rb4
-rw-r--r--activerecord/lib/active_record/connection_adapters/mysql_adapter.rb2
-rw-r--r--activerecord/lib/active_record/connection_adapters/postgresql/quoting.rb5
-rw-r--r--activerecord/lib/active_record/connection_adapters/postgresql/schema_statements.rb10
-rw-r--r--activerecord/lib/active_record/migration.rb12
-rw-r--r--activerecord/lib/active_record/migration/command_recorder.rb26
-rw-r--r--activerecord/lib/active_record/relation/merger.rb12
-rw-r--r--activerecord/lib/active_record/type/decimal.rb4
-rw-r--r--activerecord/test/cases/adapters/postgresql/schema_authorization_test.rb2
-rw-r--r--activerecord/test/cases/adapters/postgresql/schema_test.rb85
-rw-r--r--activerecord/test/cases/associations_test.rb1
-rw-r--r--activerecord/test/cases/base_test.rb28
-rw-r--r--activerecord/test/cases/invertible_migration_test.rb33
-rw-r--r--activerecord/test/cases/type/decimal_test.rb5
16 files changed, 204 insertions, 47 deletions
diff --git a/activerecord/CHANGELOG.md b/activerecord/CHANGELOG.md
index d880470d97..ec3ec06c2b 100644
--- a/activerecord/CHANGELOG.md
+++ b/activerecord/CHANGELOG.md
@@ -1,3 +1,21 @@
+* PostgreSQL, `create_schema`, `drop_schema` and `rename_table` now quote
+ schema names.
+
+ Fixes #21418.
+
+ Example:
+
+ create_schema("my.schema")
+ # CREATE SCHEMA "my.schema";
+
+ *Yves Senn*
+
+* PostgreSQL, add `:if_exists` option to `#drop_schema`. This makes it
+ possible to drop a schema that might exist without raising an exception if
+ it doesn't.
+
+ *Yves Senn*
+
* Only try to nullify has_one target association if the record is persisted.
Fixes #21223.
diff --git a/activerecord/lib/active_record/attribute_methods/read.rb b/activerecord/lib/active_record/attribute_methods/read.rb
index 2363cf7608..5197e21fa4 100644
--- a/activerecord/lib/active_record/attribute_methods/read.rb
+++ b/activerecord/lib/active_record/attribute_methods/read.rb
@@ -56,14 +56,12 @@ module ActiveRecord
end
end
- ID = 'id'.freeze
-
# Returns the value of the attribute identified by <tt>attr_name</tt> after
# it has been typecast (for example, "2004-12-12" in a date column is cast
# to a date object, like Date.new(2004, 12, 12)).
def read_attribute(attr_name, &block)
name = attr_name.to_s
- name = self.class.primary_key if name == ID
+ name = self.class.primary_key if name == 'id'.freeze
_read_attribute(name, &block)
end
diff --git a/activerecord/lib/active_record/connection_adapters/abstract_mysql_adapter.rb b/activerecord/lib/active_record/connection_adapters/abstract_mysql_adapter.rb
index b3e55a0b90..7b47539596 100644
--- a/activerecord/lib/active_record/connection_adapters/abstract_mysql_adapter.rb
+++ b/activerecord/lib/active_record/connection_adapters/abstract_mysql_adapter.rb
@@ -727,8 +727,10 @@ module ActiveRecord
# SHOW VARIABLES LIKE 'name'
def show_variable(name)
- variables = select_all("SHOW VARIABLES LIKE '#{name}'", 'SCHEMA')
+ variables = select_all("select @@#{name} as 'Value'", 'SCHEMA')
variables.first['Value'] unless variables.empty?
+ rescue ActiveRecord::StatementInvalid
+ nil
end
# Returns a table's primary key and belonging sequence.
diff --git a/activerecord/lib/active_record/connection_adapters/mysql_adapter.rb b/activerecord/lib/active_record/connection_adapters/mysql_adapter.rb
index 2ae462d773..0738c59ddf 100644
--- a/activerecord/lib/active_record/connection_adapters/mysql_adapter.rb
+++ b/activerecord/lib/active_record/connection_adapters/mysql_adapter.rb
@@ -223,7 +223,7 @@ module ActiveRecord
return @client_encoding if @client_encoding
result = exec_query(
- "SHOW VARIABLES WHERE Variable_name = 'character_set_client'",
+ "select @@character_set_client",
'SCHEMA')
@client_encoding = ENCODINGS[result.rows.last.last]
end
diff --git a/activerecord/lib/active_record/connection_adapters/postgresql/quoting.rb b/activerecord/lib/active_record/connection_adapters/postgresql/quoting.rb
index f175730551..d5879ea7df 100644
--- a/activerecord/lib/active_record/connection_adapters/postgresql/quoting.rb
+++ b/activerecord/lib/active_record/connection_adapters/postgresql/quoting.rb
@@ -31,6 +31,11 @@ module ActiveRecord
Utils.extract_schema_qualified_name(name.to_s).quoted
end
+ # Quotes schema names for use in SQL queries.
+ def quote_schema_name(name)
+ PGconn.quote_ident(name)
+ end
+
def quote_table_name_for_assignment(table, attr)
quote_column_name(attr)
end
diff --git a/activerecord/lib/active_record/connection_adapters/postgresql/schema_statements.rb b/activerecord/lib/active_record/connection_adapters/postgresql/schema_statements.rb
index d114cad16b..a3fc8fbc51 100644
--- a/activerecord/lib/active_record/connection_adapters/postgresql/schema_statements.rb
+++ b/activerecord/lib/active_record/connection_adapters/postgresql/schema_statements.rb
@@ -68,7 +68,7 @@ module ActiveRecord
execute "DROP DATABASE IF EXISTS #{quote_table_name(name)}"
end
- # Returns the list of all tables in the schema search path or a specified schema.
+ # Returns the list of all tables in the schema search path.
def tables(name = nil)
select_values("SELECT tablename FROM pg_tables WHERE schemaname = ANY(current_schemas(false))", 'SCHEMA')
end
@@ -210,12 +210,12 @@ module ActiveRecord
# Creates a schema for the given schema name.
def create_schema schema_name
- execute "CREATE SCHEMA #{schema_name}"
+ execute "CREATE SCHEMA #{quote_schema_name(schema_name)}"
end
# Drops the schema for the given schema name.
- def drop_schema schema_name
- execute "DROP SCHEMA #{schema_name} CASCADE"
+ def drop_schema(schema_name, options = {})
+ execute "DROP SCHEMA#{' IF EXISTS' if options[:if_exists]} #{quote_schema_name(schema_name)} CASCADE"
end
# Sets the schema search path to a string of comma-separated schema names.
@@ -376,7 +376,7 @@ module ActiveRecord
new_seq = "#{new_name}_#{pk}_seq"
idx = "#{table_name}_pkey"
new_idx = "#{new_name}_pkey"
- execute "ALTER TABLE #{quote_table_name(seq)} RENAME TO #{quote_table_name(new_seq)}"
+ execute "ALTER TABLE #{seq.quoted} RENAME TO #{quote_table_name(new_seq)}"
execute "ALTER INDEX #{quote_table_name(idx)} RENAME TO #{quote_table_name(new_idx)}"
end
diff --git a/activerecord/lib/active_record/migration.rb b/activerecord/lib/active_record/migration.rb
index 93e7a04f55..112d52024f 100644
--- a/activerecord/lib/active_record/migration.rb
+++ b/activerecord/lib/active_record/migration.rb
@@ -9,9 +9,9 @@ module ActiveRecord
end
end
- # Exception that can be raised to stop migrations from going backwards.
- # For example <tt>IrreversibleMigrationExample</tt> is not reversible.
- # When you rollback this migration, <tt>ActiveRecord::IrreversibleMigration</tt> is raised.
+ # Exception that can be raised to stop migrations from being rolled back.
+ # For example the following migration is not reversible.
+ # Rolling back this migration will raise an ActiveRecord::IrreversibleMigration error.
#
# class IrreversibleMigrationExample < ActiveRecord::Migration
# def change
@@ -29,7 +29,7 @@ module ActiveRecord
#
# There are two ways to mitigate this problem.
#
- # 1. Use <tt>up</tt> and <tt>down</tt> methods instead of <tt>change</tt>:
+ # 1. Define <tt>#up</tt> and <tt>#down</tt> methods instead of <tt>#change</tt>:
#
# class ReversibleMigrationExample < ActiveRecord::Migration
# def up
@@ -54,7 +54,7 @@ module ActiveRecord
# end
# end
#
- # 2. Use <tt>reversible</tt> method in <tt>change</tt> method:
+ # 2. Use the #reversible method in <tt>#change</tt> method:
#
# class ReversibleMigrationExample < ActiveRecord::Migration
# def change
@@ -238,7 +238,7 @@ module ActiveRecord
#
# rails generate migration add_fieldname_to_tablename fieldname:string
#
- # This will generate the file <tt>timestamp_add_fieldname_to_tablename</tt>, which will look like this:
+ # This will generate the file <tt>timestamp_add_fieldname_to_tablename.rb</tt>, which will look like this:
# class AddFieldnameToTablename < ActiveRecord::Migration
# def change
# add_column :tablenames, :fieldname, :string
diff --git a/activerecord/lib/active_record/migration/command_recorder.rb b/activerecord/lib/active_record/migration/command_recorder.rb
index 73dc51912a..4c4afb4dbd 100644
--- a/activerecord/lib/active_record/migration/command_recorder.rb
+++ b/activerecord/lib/active_record/migration/command_recorder.rb
@@ -5,10 +5,22 @@ module ActiveRecord
# knows how to invert the following commands:
#
# * add_column
+ # * add_foreign_key
# * add_index
+ # * add_reference
# * add_timestamps
- # * create_table
+ # * change_column_default (must supply a :from and :to option)
+ # * change_column_null
# * create_join_table
+ # * create_table
+ # * disable_extension
+ # * drop_join_table
+ # * drop_table (must supply a block)
+ # * enable_extension
+ # * remove_column (must supply a type)
+ # * remove_foreign_key (must supply a second table)
+ # * remove_index
+ # * remove_reference
# * remove_timestamps
# * rename_column
# * rename_index
@@ -17,7 +29,7 @@ module ActiveRecord
ReversibleAndIrreversibleMethods = [:create_table, :create_join_table, :rename_table, :add_column, :remove_column,
:rename_index, :rename_column, :add_index, :remove_index, :add_timestamps, :remove_timestamps,
:change_column_default, :add_reference, :remove_reference, :transaction,
- :drop_join_table, :drop_table, :execute_block, :enable_extension,
+ :drop_join_table, :drop_table, :execute_block, :enable_extension, :disable_extension,
:change_column, :execute, :remove_columns, :change_column_null,
:add_foreign_key, :remove_foreign_key
]
@@ -48,7 +60,7 @@ module ActiveRecord
@reverting = !@reverting
end
- # record +command+. +command+ should be a method name and arguments.
+ # Record +command+. +command+ should be a method name and arguments.
# For example:
#
# recorder.record(:method_name, [:arg1, :arg2])
@@ -70,10 +82,10 @@ module ActiveRecord
def inverse_of(command, args, &block)
method = :"invert_#{command}"
raise IrreversibleMigration, <<-MSG.strip_heredoc unless respond_to?(method, true)
- This migration uses #{command} that is not automatically reversible.
- There are two ways to mitigate this problem.
- 1. Define up and down methods instead of change method
- 2. Use reversible method in change method
+ This migration uses #{command}, which is not automatically reversible.
+ To make the migration reversible you can either:
+ 1. Define #up and #down methods in place of the #change method.
+ 2. Use the #reversible method to define reversible behavior.
MSG
send(method, args, &block)
end
diff --git a/activerecord/lib/active_record/relation/merger.rb b/activerecord/lib/active_record/relation/merger.rb
index 0b38666ce9..cb971eb255 100644
--- a/activerecord/lib/active_record/relation/merger.rb
+++ b/activerecord/lib/active_record/relation/merger.rb
@@ -148,11 +148,15 @@ module ActiveRecord
end
end
+ CLAUSE_METHOD_NAMES = CLAUSE_METHODS.map do |name|
+ ["#{name}_clause", "#{name}_clause="]
+ end
+
def merge_clauses
- CLAUSE_METHODS.each do |name|
- clause = relation.send("#{name}_clause")
- other_clause = other.send("#{name}_clause")
- relation.send("#{name}_clause=", clause.merge(other_clause))
+ CLAUSE_METHOD_NAMES.each do |(reader, writer)|
+ clause = relation.send(reader)
+ other_clause = other.send(reader)
+ relation.send(writer, clause.merge(other_clause))
end
end
end
diff --git a/activerecord/lib/active_record/type/decimal.rb b/activerecord/lib/active_record/type/decimal.rb
index f200a92d10..f5b145230d 100644
--- a/activerecord/lib/active_record/type/decimal.rb
+++ b/activerecord/lib/active_record/type/decimal.rb
@@ -14,7 +14,7 @@ module ActiveRecord
private
def cast_value(value)
- case value
+ casted_value = case value
when ::Float
convert_float_to_big_decimal(value)
when ::Numeric, ::String
@@ -26,6 +26,8 @@ module ActiveRecord
cast_value(value.to_s)
end
end
+
+ scale ? casted_value.round(scale) : casted_value
end
def convert_float_to_big_decimal(value)
diff --git a/activerecord/test/cases/adapters/postgresql/schema_authorization_test.rb b/activerecord/test/cases/adapters/postgresql/schema_authorization_test.rb
index fa6584eae5..a0afd922b2 100644
--- a/activerecord/test/cases/adapters/postgresql/schema_authorization_test.rb
+++ b/activerecord/test/cases/adapters/postgresql/schema_authorization_test.rb
@@ -31,7 +31,7 @@ class SchemaAuthorizationTest < ActiveRecord::PostgreSQLTestCase
set_session_auth
@connection.execute "RESET search_path"
USERS.each do |u|
- @connection.execute "DROP SCHEMA #{u} CASCADE"
+ @connection.drop_schema u
@connection.execute "DROP USER #{u}"
end
end
diff --git a/activerecord/test/cases/adapters/postgresql/schema_test.rb b/activerecord/test/cases/adapters/postgresql/schema_test.rb
index 35d5581aa7..ea7e5ac587 100644
--- a/activerecord/test/cases/adapters/postgresql/schema_test.rb
+++ b/activerecord/test/cases/adapters/postgresql/schema_test.rb
@@ -2,7 +2,17 @@ require "cases/helper"
require 'models/default'
require 'support/schema_dumping_helper'
+module PGSchemaHelper
+ def with_schema_search_path(schema_search_path)
+ @connection.schema_search_path = schema_search_path
+ yield if block_given?
+ ensure
+ @connection.schema_search_path = "'$user', public"
+ end
+end
+
class SchemaTest < ActiveRecord::PostgreSQLTestCase
+ include PGSchemaHelper
self.use_transactional_tests = false
SCHEMA_NAME = 'test_schema'
@@ -84,8 +94,8 @@ class SchemaTest < ActiveRecord::PostgreSQLTestCase
end
teardown do
- @connection.execute "DROP SCHEMA #{SCHEMA2_NAME} CASCADE"
- @connection.execute "DROP SCHEMA #{SCHEMA_NAME} CASCADE"
+ @connection.drop_schema SCHEMA2_NAME, if_exists: true
+ @connection.drop_schema SCHEMA_NAME, if_exists: true
end
def test_schema_names
@@ -121,10 +131,17 @@ class SchemaTest < ActiveRecord::PostgreSQLTestCase
assert !@connection.schema_names.include?("test_schema3")
end
+ def test_drop_schema_if_exists
+ @connection.create_schema "some_schema"
+ assert_includes @connection.schema_names, "some_schema"
+ @connection.drop_schema "some_schema", if_exists: true
+ assert_not_includes @connection.schema_names, "some_schema"
+ end
+
def test_habtm_table_name_with_schema
+ ActiveRecord::Base.connection.drop_schema "music", if_exists: true
+ ActiveRecord::Base.connection.create_schema "music"
ActiveRecord::Base.connection.execute <<-SQL
- DROP SCHEMA IF EXISTS music CASCADE;
- CREATE SCHEMA music;
CREATE TABLE music.albums (id serial primary key);
CREATE TABLE music.songs (id serial primary key);
CREATE TABLE music.albums_songs (album_id integer, song_id integer);
@@ -134,12 +151,16 @@ class SchemaTest < ActiveRecord::PostgreSQLTestCase
Album.create
assert_equal song, Song.includes(:albums).references(:albums).first
ensure
- ActiveRecord::Base.connection.execute "DROP SCHEMA music CASCADE;"
+ ActiveRecord::Base.connection.drop_schema "music", if_exists: true
end
- def test_raise_drop_schema_with_nonexisting_schema
+ def test_drop_schema_with_nonexisting_schema
assert_raises(ActiveRecord::StatementInvalid) do
- @connection.drop_schema "test_schema3"
+ @connection.drop_schema "idontexist"
+ end
+
+ assert_nothing_raised do
+ @connection.drop_schema "idontexist", if_exists: true
end
end
@@ -404,13 +425,6 @@ class SchemaTest < ActiveRecord::PostgreSQLTestCase
end
end
- def with_schema_search_path(schema_search_path)
- @connection.schema_search_path = schema_search_path
- yield if block_given?
- ensure
- @connection.schema_search_path = "'$user', public"
- end
-
def do_dump_index_tests_for_schema(this_schema_name, first_index_column_name, second_index_column_name, third_index_column_name, fourth_index_column_name)
with_schema_search_path(this_schema_name) do
indexes = @connection.indexes(TABLE_NAME).sort_by(&:name)
@@ -462,14 +476,14 @@ class SchemaForeignKeyTest < ActiveRecord::PostgreSQLTestCase
ensure
@connection.drop_table "wagons", if_exists: true
@connection.drop_table "my_schema.trains", if_exists: true
- @connection.execute "DROP SCHEMA IF EXISTS my_schema"
+ @connection.drop_schema "my_schema", if_exists: true
end
end
class DefaultsUsingMultipleSchemasAndDomainTest < ActiveRecord::PostgreSQLTestCase
setup do
@connection = ActiveRecord::Base.connection
- @connection.execute "DROP SCHEMA IF EXISTS schema_1 CASCADE"
+ @connection.drop_schema "schema_1", if_exists: true
@connection.execute "CREATE SCHEMA schema_1"
@connection.execute "CREATE DOMAIN schema_1.text AS text"
@connection.execute "CREATE DOMAIN schema_1.varchar AS varchar"
@@ -487,7 +501,7 @@ class DefaultsUsingMultipleSchemasAndDomainTest < ActiveRecord::PostgreSQLTestCa
teardown do
@connection.schema_search_path = @old_search_path
- @connection.execute "DROP SCHEMA IF EXISTS schema_1 CASCADE"
+ @connection.drop_schema "schema_1", if_exists: true
Default.reset_column_information
end
@@ -519,3 +533,40 @@ class DefaultsUsingMultipleSchemasAndDomainTest < ActiveRecord::PostgreSQLTestCa
assert_equal "foo'::bar", Default.new.string_col
end
end
+
+class SchemaWithDotsTest < ActiveRecord::PostgreSQLTestCase
+ include PGSchemaHelper
+ self.use_transactional_tests = false
+
+ setup do
+ @connection = ActiveRecord::Base.connection
+ @connection.create_schema "my.schema"
+ end
+
+ teardown do
+ @connection.drop_schema "my.schema", if_exists: true
+ end
+
+ test "rename_table" do
+ with_schema_search_path('"my.schema"') do
+ @connection.create_table :posts
+ @connection.rename_table :posts, :articles
+ assert_equal ["articles"], @connection.tables
+ end
+ end
+
+ test "Active Record basics" do
+ with_schema_search_path('"my.schema"') do
+ @connection.create_table :articles do |t|
+ t.string :title
+ end
+ article_class = Class.new(ActiveRecord::Base) do
+ self.table_name = '"my.schema".articles'
+ end
+
+ article_class.create!(title: "zOMG, welcome to my blorgh!")
+ welcome_article = article_class.last
+ assert_equal "zOMG, welcome to my blorgh!", welcome_article.title
+ end
+ end
+end
diff --git a/activerecord/test/cases/associations_test.rb b/activerecord/test/cases/associations_test.rb
index 61e1dd0717..01a058918a 100644
--- a/activerecord/test/cases/associations_test.rb
+++ b/activerecord/test/cases/associations_test.rb
@@ -12,7 +12,6 @@ require 'models/tag'
require 'models/tagging'
require 'models/person'
require 'models/reader'
-require 'models/parrot'
require 'models/ship_part'
require 'models/ship'
require 'models/liquid'
diff --git a/activerecord/test/cases/base_test.rb b/activerecord/test/cases/base_test.rb
index 382adbbdc7..0edb8a8901 100644
--- a/activerecord/test/cases/base_test.rb
+++ b/activerecord/test/cases/base_test.rb
@@ -946,6 +946,34 @@ class BasicsTest < ActiveRecord::TestCase
assert_equal BigDecimal("1000234000567.95"), m1.big_bank_balance
end
+ def test_numeric_fields_with_scale
+ m = NumericData.new(
+ :bank_balance => 1586.43122334,
+ :big_bank_balance => BigDecimal("234000567.952344"),
+ :world_population => 6000000000,
+ :my_house_population => 3
+ )
+ assert m.save
+
+ m1 = NumericData.find(m.id)
+ assert_not_nil m1
+
+ # As with migration_test.rb, we should make world_population >= 2**62
+ # to cover 64-bit platforms and test it is a Bignum, but the main thing
+ # is that it's an Integer.
+ assert_kind_of Integer, m1.world_population
+ assert_equal 6000000000, m1.world_population
+
+ assert_kind_of Fixnum, m1.my_house_population
+ assert_equal 3, m1.my_house_population
+
+ assert_kind_of BigDecimal, m1.bank_balance
+ assert_equal BigDecimal("1586.43"), m1.bank_balance
+
+ assert_kind_of BigDecimal, m1.big_bank_balance
+ assert_equal BigDecimal("234000567.95"), m1.big_bank_balance
+ end
+
def test_auto_id
auto = AutoId.new
auto.save
diff --git a/activerecord/test/cases/invertible_migration_test.rb b/activerecord/test/cases/invertible_migration_test.rb
index 1664c9e25d..84b0ff8fcb 100644
--- a/activerecord/test/cases/invertible_migration_test.rb
+++ b/activerecord/test/cases/invertible_migration_test.rb
@@ -93,6 +93,18 @@ module ActiveRecord
end
end
+ class DisableExtension1 < SilentMigration
+ def change
+ enable_extension "hstore"
+ end
+ end
+
+ class DisableExtension2 < SilentMigration
+ def change
+ disable_extension "hstore"
+ end
+ end
+
class LegacyMigration < ActiveRecord::Migration
def self.up
create_table("horses") do |t|
@@ -255,6 +267,27 @@ module ActiveRecord
assert_equal "Sekitoba", Horse.new.name
end
+ if current_adapter?(:PostgreSQLAdapter)
+ def test_migrate_enable_and_disable_extension
+ migration1 = InvertibleMigration.new
+ migration2 = DisableExtension1.new
+ migration3 = DisableExtension2.new
+
+ migration1.migrate(:up)
+ migration2.migrate(:up)
+ assert_equal true, Horse.connection.extension_enabled?('hstore')
+
+ migration3.migrate(:up)
+ assert_equal false, Horse.connection.extension_enabled?('hstore')
+
+ migration3.migrate(:down)
+ assert_equal true, Horse.connection.extension_enabled?('hstore')
+
+ migration2.migrate(:down)
+ assert_equal false, Horse.connection.extension_enabled?('hstore')
+ end
+ end
+
def test_revert_order
block = Proc.new{|t| t.string :name }
recorder = ActiveRecord::Migration::CommandRecorder.new(ActiveRecord::Base.connection)
diff --git a/activerecord/test/cases/type/decimal_test.rb b/activerecord/test/cases/type/decimal_test.rb
index fe49d0e79a..01ee36b892 100644
--- a/activerecord/test/cases/type/decimal_test.rb
+++ b/activerecord/test/cases/type/decimal_test.rb
@@ -25,6 +25,11 @@ module ActiveRecord
assert_equal BigDecimal("0.33"), type.cast(Rational(1, 3))
end
+ def test_type_cast_decimal_from_rational_with_precision_and_scale
+ type = Decimal.new(precision: 4, scale: 2)
+ assert_equal BigDecimal("0.33"), type.cast(Rational(1, 3))
+ end
+
def test_type_cast_decimal_from_rational_without_precision_defaults_to_18_36
type = Decimal.new
assert_equal BigDecimal("0.333333333333333333E0"), type.cast(Rational(1, 3))