diff options
22 files changed, 159 insertions, 62 deletions
@@ -60,7 +60,7 @@ platforms :ruby do gem 'nokogiri', '>= 1.4.5' # AR - gem 'sqlite3', '~> 1.3.5' + gem 'sqlite3', '~> 1.3.6' group :db do gem 'pg', '>= 0.11.0' diff --git a/activerecord/CHANGELOG.md b/activerecord/CHANGELOG.md index 3328f80fdd..d19e0c9e9b 100644 --- a/activerecord/CHANGELOG.md +++ b/activerecord/CHANGELOG.md @@ -633,7 +633,7 @@ has_one :account end - user.build_account{ |a| a.credit_limit => 100.0 } + user.build_account{ |a| a.credit_limit = 100.0 } The block is called after the instance has been initialized. *Andrew White* diff --git a/activerecord/lib/active_record/connection_adapters/abstract/schema_definitions.rb b/activerecord/lib/active_record/connection_adapters/abstract/schema_definitions.rb index f17baec722..df78ba6c5a 100644 --- a/activerecord/lib/active_record/connection_adapters/abstract/schema_definitions.rb +++ b/activerecord/lib/active_record/connection_adapters/abstract/schema_definitions.rb @@ -23,7 +23,7 @@ module ActiveRecord end def sql_type - base.type_to_sql(type.to_sym, limit, precision, scale) rescue type + base.type_to_sql(type.to_sym, limit, precision, scale) end def to_sql diff --git a/activerecord/lib/active_record/connection_adapters/sqlite3_adapter.rb b/activerecord/lib/active_record/connection_adapters/sqlite3_adapter.rb index 5b9c9770df..d4ffa82b17 100644 --- a/activerecord/lib/active_record/connection_adapters/sqlite3_adapter.rb +++ b/activerecord/lib/active_record/connection_adapters/sqlite3_adapter.rb @@ -21,10 +21,6 @@ module ActiveRecord config[:database] = File.expand_path(config[:database], Rails.root) end - unless 'sqlite3' == config[:adapter] - raise ArgumentError, 'adapter name should be "sqlite3"' - end - db = SQLite3::Database.new( config[:database], :results_as_hash => true @@ -195,7 +191,7 @@ module ActiveRecord :decimal => { :name => "decimal" }, :datetime => { :name => "datetime" }, :timestamp => { :name => "datetime" }, - :time => { :name => "time" }, + :time => { :name => "datetime" }, :date => { :name => "date" }, :binary => { :name => "blob" }, :boolean => { :name => "boolean" } diff --git a/activerecord/lib/active_record/relation/calculations.rb b/activerecord/lib/active_record/relation/calculations.rb index aa2f325f74..31d99f0192 100644 --- a/activerecord/lib/active_record/relation/calculations.rb +++ b/activerecord/lib/active_record/relation/calculations.rb @@ -140,24 +140,25 @@ module ActiveRecord # # => ['0', '27761', '173'] # def pluck(column_name) - key = column_name.to_s.split('.', 2).last - if column_name.is_a?(Symbol) && column_names.include?(column_name.to_s) column_name = "#{table_name}.#{column_name}" end result = klass.connection.select_all(select(column_name).arel, nil, bind_values) - types = result.column_types.merge klass.column_types - column = types[key] + + key = result.columns.first + column = klass.column_types.fetch(key) { + result.column_types.fetch(key) { + Class.new { def type_cast(v); v; end }.new + } + } result.map do |attributes| raise ArgumentError, "Pluck expects to select just one attribute: #{attributes.inspect}" unless attributes.one? - value = klass.initialize_attributes(attributes).first[1] - if column - column.type_cast value - else - value - end + + value = klass.initialize_attributes(attributes).values.first + + column.type_cast(value) end end diff --git a/activerecord/lib/active_record/session_store.rb b/activerecord/lib/active_record/session_store.rb index ed47a26749..5a256b040b 100644 --- a/activerecord/lib/active_record/session_store.rb +++ b/activerecord/lib/active_record/session_store.rb @@ -201,10 +201,10 @@ module ActiveRecord class << self alias :data_column_name :data_column - + # Use the ActiveRecord::Base.connection by default. attr_writer :connection - + # Use the ActiveRecord::Base.connection_pool by default. attr_writer :connection_pool @@ -218,12 +218,12 @@ module ActiveRecord # Look up a session by id and unmarshal its data if found. def find_by_session_id(session_id) - if record = connection.select_one("SELECT * FROM #{@@table_name} WHERE #{@@session_id_column}=#{connection.quote(session_id)}") + if record = connection.select_one("SELECT * FROM #{@@table_name} WHERE #{@@session_id_column}=#{connection.quote(session_id.to_s)}") new(:session_id => session_id, :marshaled_data => record['data']) end end end - + delegate :connection, :connection=, :connection_pool, :connection_pool=, :to => self attr_reader :session_id, :new_record @@ -241,6 +241,11 @@ module ActiveRecord @new_record = @marshaled_data.nil? end + # Returns true if the record is persisted, i.e. it's not a new record + def persisted? + !@new_record + end + # Lazy-unmarshal session state. def data unless @data @@ -287,7 +292,7 @@ module ActiveRecord connect = connection connect.delete <<-end_sql, 'Destroy session' DELETE FROM #{table_name} - WHERE #{connect.quote_column_name(session_id_column)}=#{connect.quote(session_id)} + WHERE #{connect.quote_column_name(session_id_column)}=#{connect.quote(session_id.to_s)} end_sql end end diff --git a/activerecord/test/cases/adapters/sqlite3/sqlite3_adapter_test.rb b/activerecord/test/cases/adapters/sqlite3/sqlite3_adapter_test.rb index 17bde6cb62..f786452f94 100644 --- a/activerecord/test/cases/adapters/sqlite3/sqlite3_adapter_test.rb +++ b/activerecord/test/cases/adapters/sqlite3/sqlite3_adapter_test.rb @@ -35,6 +35,11 @@ module ActiveRecord assert(!result.rows.first.include?("blob"), "should not store blobs") end + def test_time_column + owner = Owner.create!(:eats_at => Time.utc(1995,1,1,6,0)) + assert_match /1995-01-01/, owner.reload.eats_at.to_s + end + def test_exec_insert column = @conn.columns('items').find { |col| col.name == 'number' } vals = [[column, 10]] @@ -58,18 +63,6 @@ module ActiveRecord end end - def test_connection_no_adapter - assert_raises(ArgumentError) do - Base.sqlite3_connection :database => ':memory:' - end - end - - def test_connection_wrong_adapter - assert_raises(ArgumentError) do - Base.sqlite3_connection :database => ':memory:',:adapter => 'vuvuzela' - end - end - def test_bad_timeout assert_raises(TypeError) do Base.sqlite3_connection :database => ':memory:', diff --git a/activerecord/test/cases/base_test.rb b/activerecord/test/cases/base_test.rb index d7d14856d0..66a16d8b5f 100644 --- a/activerecord/test/cases/base_test.rb +++ b/activerecord/test/cases/base_test.rb @@ -522,7 +522,7 @@ class BasicsTest < ActiveRecord::TestCase end # Oracle, and Sybase do not have a TIME datatype. - unless current_adapter?(:OracleAdapter, :SybaseAdapter) + unless current_adapter?(:OracleAdapter, :SybaseAdapter, :SQLite3Adapter) def test_utc_as_time_zone Topic.default_timezone = :utc attributes = { "bonus_time" => "5:42:00AM" } @@ -764,6 +764,9 @@ class BasicsTest < ActiveRecord::TestCase end def test_multiparameter_attributes_on_time_will_ignore_hour_if_missing + ActiveRecord::Base.time_zone_aware_attributes = false + ActiveRecord::Base.default_timezone = :local + Time.zone = nil attributes = { "written_on(1i)" => "2004", "written_on(2i)" => "12", "written_on(3i)" => "12", "written_on(5i)" => "12", "written_on(6i)" => "02" @@ -870,7 +873,7 @@ class BasicsTest < ActiveRecord::TestCase end # Oracle, and Sybase do not have a TIME datatype. - unless current_adapter?(:OracleAdapter, :SybaseAdapter) + unless current_adapter?(:OracleAdapter, :SybaseAdapter, :SQLite3Adapter) def test_multiparameter_attributes_on_time_only_column_with_time_zone_aware_attributes_does_not_do_time_zone_conversion ActiveRecord::Base.time_zone_aware_attributes = true ActiveRecord::Base.default_timezone = :utc @@ -891,6 +894,9 @@ class BasicsTest < ActiveRecord::TestCase end def test_multiparameter_attributes_on_time_with_empty_seconds + ActiveRecord::Base.time_zone_aware_attributes = false + ActiveRecord::Base.default_timezone = :local + Time.zone = nil attributes = { "written_on(1i)" => "2004", "written_on(2i)" => "6", "written_on(3i)" => "24", "written_on(4i)" => "16", "written_on(5i)" => "24", "written_on(6i)" => "" @@ -946,7 +952,7 @@ class BasicsTest < ActiveRecord::TestCase def test_attributes_on_dummy_time # Oracle, and Sybase do not have a TIME datatype. - return true if current_adapter?(:OracleAdapter, :SybaseAdapter) + return true if current_adapter?(:OracleAdapter, :SybaseAdapter, :SQLite3Adapter) attributes = { "bonus_time" => "5:42:00AM" diff --git a/activerecord/test/cases/calculations_test.rb b/activerecord/test/cases/calculations_test.rb index c9a70bae77..041f8ffb7c 100644 --- a/activerecord/test/cases/calculations_test.rb +++ b/activerecord/test/cases/calculations_test.rb @@ -468,6 +468,13 @@ class CalculationsTest < ActiveRecord::TestCase def test_pluck_with_selection_clause assert_equal [50, 53, 55, 60], Account.pluck('DISTINCT credit_limit').sort + assert_equal [50, 53, 55, 60], Account.pluck('DISTINCT accounts.credit_limit').sort + assert_equal [50, 53, 55, 60], Account.pluck('DISTINCT(credit_limit)').sort + + # MySQL returns "SUM(DISTINCT(credit_limit))" as the column name unless + # an alias is provided. Without the alias, the column cannot be found + # and properly typecast. + assert_equal [50 + 53 + 55 + 60], Account.pluck('SUM(DISTINCT(credit_limit)) as credit_limit') end def test_pluck_expects_a_single_selection diff --git a/activerecord/test/cases/migration/change_schema_test.rb b/activerecord/test/cases/migration/change_schema_test.rb index f0b1f74bd3..ab61a4dcef 100644 --- a/activerecord/test/cases/migration/change_schema_test.rb +++ b/activerecord/test/cases/migration/change_schema_test.rb @@ -83,7 +83,6 @@ module ActiveRecord t.column :one_int, :integer, :limit => 1 t.column :four_int, :integer, :limit => 4 t.column :eight_int, :integer, :limit => 8 - t.column :eleven_int, :integer, :limit => 11 end columns = connection.columns(:testings) @@ -94,20 +93,17 @@ module ActiveRecord one = columns.detect { |c| c.name == "one_int" } four = columns.detect { |c| c.name == "four_int" } eight = columns.detect { |c| c.name == "eight_int" } - eleven = columns.detect { |c| c.name == "eleven_int" } if current_adapter?(:PostgreSQLAdapter) assert_equal 'integer', default.sql_type assert_equal 'smallint', one.sql_type assert_equal 'integer', four.sql_type assert_equal 'bigint', eight.sql_type - assert_equal 'integer', eleven.sql_type elsif current_adapter?(:MysqlAdapter) or current_adapter?(:Mysql2Adapter) assert_match 'int(11)', default.sql_type assert_match 'tinyint', one.sql_type assert_match 'int', four.sql_type assert_match 'bigint', eight.sql_type - assert_match 'int(11)', eleven.sql_type elsif current_adapter?(:OracleAdapter) assert_equal 'NUMBER(38)', default.sql_type assert_equal 'NUMBER(1)', one.sql_type diff --git a/activerecord/test/cases/migration/column_attributes_test.rb b/activerecord/test/cases/migration/column_attributes_test.rb index 409a558f5c..18f8d82bfe 100644 --- a/activerecord/test/cases/migration/column_attributes_test.rb +++ b/activerecord/test/cases/migration/column_attributes_test.rb @@ -183,6 +183,16 @@ module ActiveRecord assert_instance_of TrueClass, bob.male? assert_kind_of BigDecimal, bob.wealth end + + def test_out_of_range_limit_should_raise + skip("MySQL and PostgreSQL only") unless current_adapter?(:MysqlAdapter, :Mysql2Adapter, :PostgreSQLAdapter) + + assert_raise(ActiveRecordError) { add_column :test_models, :integer_too_big, :integer, :limit => 10 } + + unless current_adapter?(:PostgreSQLAdapter) + assert_raise(ActiveRecordError) { add_column :test_models, :text_too_big, :integer, :limit => 0xfffffffff } + end + end end end end diff --git a/activerecord/test/cases/migration_test.rb b/activerecord/test/cases/migration_test.rb index f788690b0d..cad93936c9 100644 --- a/activerecord/test/cases/migration_test.rb +++ b/activerecord/test/cases/migration_test.rb @@ -375,6 +375,27 @@ class MigrationTest < ActiveRecord::TestCase end end + def test_out_of_range_limit_should_raise + skip("MySQL and PostgreSQL only") unless current_adapter?(:MysqlAdapter, :Mysql2Adapter, :PostgreSQLAdapter) + + Person.connection.drop_table :test_limits rescue nil + assert_raise(ActiveRecord::ActiveRecordError, "integer limit didn't raise") do + Person.connection.create_table :test_integer_limits, :force => true do |t| + t.column :bigone, :integer, :limit => 10 + end + end + + unless current_adapter?(:PostgreSQLAdapter) + assert_raise(ActiveRecord::ActiveRecordError, "text limit didn't raise") do + Person.connection.create_table :test_text_limits, :force => true do |t| + t.column :bigtext, :text, :limit => 0xfffffffff + end + end + end + + Person.connection.drop_table :test_limits rescue nil + end + protected def with_env_tz(new_tz = 'US/Eastern') old_tz, ENV['TZ'] = ENV['TZ'], new_tz @@ -883,8 +904,8 @@ class CopyMigrationsTest < ActiveRecord::TestCase def test_skipping_migrations @migrations_path = MIGRATIONS_ROOT + "/valid_with_timestamps" @existing_migrations = Dir[@migrations_path + "/*.rb"] - - sources = {} + + sources = {} sources[:bukkits] = MIGRATIONS_ROOT + "/to_copy_with_timestamps" sources[:omg] = MIGRATIONS_ROOT + "/to_copy_with_name_collision" diff --git a/activerecord/test/cases/session_store/sql_bypass.rb b/activerecord/test/cases/session_store/sql_bypass_test.rb index 7402b2afd6..6749d4ce98 100644 --- a/activerecord/test/cases/session_store/sql_bypass.rb +++ b/activerecord/test/cases/session_store/sql_bypass_test.rb @@ -18,6 +18,11 @@ module ActiveRecord assert !Session.table_exists? end + def test_new_record? + s = SqlBypass.new :data => 'foo', :session_id => 10 + assert s.new_record?, 'this is a new record!' + end + def test_persisted? s = SqlBypass.new :data => 'foo', :session_id => 10 assert !s.persisted?, 'this is a new record!' diff --git a/activerecord/test/schema/schema.rb b/activerecord/test/schema/schema.rb index 6422cf6415..3fc58c25b1 100644 --- a/activerecord/test/schema/schema.rb +++ b/activerecord/test/schema/schema.rb @@ -431,6 +431,7 @@ ActiveRecord::Schema.define do t.string :name t.column :updated_at, :datetime t.column :happy_at, :datetime + t.column :eats_at, :time t.string :essay_id end diff --git a/activesupport/lib/active_support/core_ext/string/output_safety.rb b/activesupport/lib/active_support/core_ext/string/output_safety.rb index 6bda970e40..f98d5b3777 100644 --- a/activesupport/lib/active_support/core_ext/string/output_safety.rb +++ b/activesupport/lib/active_support/core_ext/string/output_safety.rb @@ -150,6 +150,20 @@ module ActiveSupport #:nodoc: dup.concat(other) end + def %(args) + args = Array(args) + + args.map! do |arg| + if !html_safe? || arg.html_safe? + arg + else + ERB::Util.h(arg) + end + end + + self.class.new(super(args)) + end + def html_safe? defined?(@html_safe) && @html_safe end diff --git a/activesupport/lib/active_support/deprecation/behaviors.rb b/activesupport/lib/active_support/deprecation/behaviors.rb index 9102537810..fc962dcb57 100644 --- a/activesupport/lib/active_support/deprecation/behaviors.rb +++ b/activesupport/lib/active_support/deprecation/behaviors.rb @@ -16,9 +16,9 @@ module ActiveSupport # # Available behaviors: # - # [+stderr+] Log all deprecation warnings to +$stderr+. + # [+stderr+] Log all deprecation warnings to <tt>$stderr</tt>. # [+log+] Log all deprecation warnings to +Rails.logger+. - # [+notify] Use +ActiveSupport::Notifications+ to notify +deprecation.rails+. + # [+notify+] Use <tt>ActiveSupport::Notifications</tt> to notify +deprecation.rails+. # [+silence+] Do nothing. # # Setting behaviors only affects deprecations that happen after boot time. diff --git a/activesupport/test/core_ext/string_ext_test.rb b/activesupport/test/core_ext/string_ext_test.rb index 9010a4a716..eee2caa60e 100644 --- a/activesupport/test/core_ext/string_ext_test.rb +++ b/activesupport/test/core_ext/string_ext_test.rb @@ -439,6 +439,30 @@ class OutputSafetyTest < ActiveSupport::TestCase assert @other_string.html_safe? end + test "Concatting safe onto unsafe with % yields unsafe" do + @other_string = "other%s" + string = @string.html_safe + + @other_string = @other_string % string + assert !@other_string.html_safe? + end + + test "Concatting unsafe onto safe with % yields escaped safe" do + @other_string = "other%s".html_safe + string = @other_string % "<foo>" + + assert_equal "other<foo>", string + assert string.html_safe? + end + + test "Concatting safe onto safe with % yields safe" do + @other_string = "other%s".html_safe + string = @string.html_safe + + @other_string = @other_string % string + assert @other_string.html_safe? + end + test "Concatting a fixnum to safe always yields safe" do string = @string.html_safe string = string.concat(13) diff --git a/guides/source/active_record_querying.textile b/guides/source/active_record_querying.textile index a9cb424eaa..294ef25b33 100644 --- a/guides/source/active_record_querying.textile +++ b/guides/source/active_record_querying.textile @@ -1260,6 +1260,24 @@ with Client.pluck(:id) </ruby> +h3. +ids+ + ++ids+ can be used to pluck all the IDs for the relation using the table's primary key. + +<ruby> +Person.ids +# SELECT id FROM people +</ruby> + +<ruby> +class Person < ActiveRecord::Base + self.primary_key = "person_id" +end + +Person.ids +# SELECT person_id FROM people +</ruby> + h3. Existence of Objects If you simply want to check for the existence of the object there's a method called +exists?+. This method will query the database using the same query as +find+, but instead of returning an object or collection of objects it will return either +true+ or +false+. diff --git a/guides/source/getting_started.textile b/guides/source/getting_started.textile index e93a94448a..f32588d591 100644 --- a/guides/source/getting_started.textile +++ b/guides/source/getting_started.textile @@ -1332,7 +1332,7 @@ So first, we'll wire up the Post show template <p> <strong>Text:</strong> - <%= @post.texthttp://beginningruby.org/ %> + <%= @post.text %> </p> <h2>Add a comment:</h2> @@ -1391,7 +1391,7 @@ template. This is where we want the comment to show, so let's add that to the <p> <strong>Text:</strong> - <%= @post.texthttp://beginningruby.org/ %> + <%= @post.text %> </p> <h2>Comments</h2> @@ -1466,7 +1466,7 @@ following: <p> <strong>Text:</strong> - <%= @post.texthttp://beginningruby.org/ %> + <%= @post.text %> </p> <h2>Comments</h2> @@ -1528,7 +1528,7 @@ Then you make the +app/views/posts/show.html.erb+ look like the following: <p> <strong>Text:</strong> - <%= @post.texthttp://beginningruby.org/ %> + <%= @post.text %> </p> <h2>Add a comment:</h2> diff --git a/guides/source/layouts_and_rendering.textile b/guides/source/layouts_and_rendering.textile index e4a1fd6951..b0a87a5981 100644 --- a/guides/source/layouts_and_rendering.textile +++ b/guides/source/layouts_and_rendering.textile @@ -860,12 +860,6 @@ You can supply a hash of additional HTML options: <%= image_tag "icons/delete.gif", {:height => 45} %> </erb> -You can also supply an alternate image to show on mouseover: - -<erb> -<%= image_tag "home.gif", :onmouseover => "menu/home_highlight.gif" %> -</erb> - You can supply alternate text for the image which will be used if the user has images turned off in their browser. If you do not specify an alt text explicitly, it defaults to the file name of the file, capitalized and with no extension. For example, these two image tags would return the same code: <erb> diff --git a/railties/lib/rails/generators/app_base.rb b/railties/lib/rails/generators/app_base.rb index d661c62148..10ad475d55 100644 --- a/railties/lib/rails/generators/app_base.rb +++ b/railties/lib/rails/generators/app_base.rb @@ -249,13 +249,14 @@ module Rails # We unset temporary bundler variables to load proper bundler and Gemfile. # # Thanks to James Tucker for the Gem tricks involved in this call. + _bundle_command = Gem.bin_path('bundler', 'bundle') - bundle_gemfile, rubyopt = ENV['BUNDLE_GEMFILE'], ENV['RUBYOPT'] - ENV['BUNDLE_GEMFILE'], ENV['RUBYOPT'] = "", "" + bundle_bin_path, bundle_gemfile, rubyopt = ENV['BUNDLE_BIN_PATH'], ENV['BUNDLE_GEMFILE'], ENV['RUBYOPT'] + ENV['BUNDLE_BIN_PATH'], ENV['BUNDLE_GEMFILE'], ENV['RUBYOPT'] = "", "", "" - print `"#{Gem.ruby}" "#{Gem.bin_path('bundler', 'bundle')}" #{command}` + print `"#{Gem.ruby}" "#{_bundle_command}" #{command}` - ENV['BUNDLE_GEMFILE'], ENV['RUBYOPT'] = bundle_gemfile, rubyopt + ENV['BUNDLE_BIN_PATH'], ENV['BUNDLE_GEMFILE'], ENV['RUBYOPT'] = bundle_bin_path, bundle_gemfile, rubyopt end def run_bundle diff --git a/railties/test/generators/plugin_new_generator_test.rb b/railties/test/generators/plugin_new_generator_test.rb index 51374e5f3f..b0e1865b26 100644 --- a/railties/test/generators/plugin_new_generator_test.rb +++ b/railties/test/generators/plugin_new_generator_test.rb @@ -99,7 +99,13 @@ class PluginNewGeneratorTest < Rails::Generators::TestCase end def test_generation_runs_bundle_install_with_full_and_mountable - result = run_generator [destination_root, "--mountable", "--full"] + result = run_generator [destination_root, "--mountable", "--full", "--dev"] + assert_file "#{destination_root}/Gemfile.lock" do |contents| + assert_match(/bukkits/, contents) + end + assert_match(/run bundle install/, result) + assert_match(/Using bukkits \(0\.0\.1\)/, result) + assert_match(/Your bundle is complete/, result) assert_equal 1, result.scan("Your bundle is complete").size end @@ -348,4 +354,3 @@ protected silence(:stdout){ generator.send(*args, &block) } end end - |