diff options
17 files changed, 66 insertions, 58 deletions
diff --git a/activerecord/CHANGELOG.md b/activerecord/CHANGELOG.md index 487352fce6..f53cb6ad51 100644 --- a/activerecord/CHANGELOG.md +++ b/activerecord/CHANGELOG.md @@ -1,3 +1,18 @@ +* Type cast hstore values on write, so that the value is consistent + with reading from the database. + + Example: + + x = Hstore.new tags: {"bool" => true, "number" => 5} + + # Before: + x.tags # => {"bool" => true, "number" => 5} + + # After: + x.tags # => {"bool" => "true", "number" => "5"} + + *Yves Senn* , *Severin Schoepke* + * Fix multidimensional PG arrays containing non-string items. *Yves Senn* diff --git a/activerecord/lib/active_record/connection_adapters/abstract/query_cache.rb b/activerecord/lib/active_record/connection_adapters/abstract/query_cache.rb index e6b3c8ec9f..7aae297cdc 100644 --- a/activerecord/lib/active_record/connection_adapters/abstract/query_cache.rb +++ b/activerecord/lib/active_record/connection_adapters/abstract/query_cache.rb @@ -81,14 +81,7 @@ module ActiveRecord else @query_cache[sql][binds] = yield end - - # FIXME: we should guarantee that all cached items are Result - # objects. Then we can avoid this conditional - if ActiveRecord::Result === result - result.dup - else - result.collect { |row| row.dup } - end + result.dup end # If arel is locked this is a SELECT ... FOR UPDATE or somesuch. Such diff --git a/activerecord/lib/active_record/connection_adapters/abstract/quoting.rb b/activerecord/lib/active_record/connection_adapters/abstract/quoting.rb index d18b9c991f..c8fa4ef9af 100644 --- a/activerecord/lib/active_record/connection_adapters/abstract/quoting.rb +++ b/activerecord/lib/active_record/connection_adapters/abstract/quoting.rb @@ -15,7 +15,6 @@ module ActiveRecord return "'#{quote_string(value)}'" unless column case column.type - when :binary then "'#{quote_string(column.string_to_binary(value))}'" when :integer then value.to_i.to_s when :float then value.to_f.to_s else 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 0be4b5cb19..063b19871a 100644 --- a/activerecord/lib/active_record/connection_adapters/abstract/schema_definitions.rb +++ b/activerecord/lib/active_record/connection_adapters/abstract/schema_definitions.rb @@ -16,9 +16,6 @@ module ActiveRecord # +columns+ attribute of said TableDefinition object, in order to be used # for generating a number of table creation or table changing SQL statements. class ColumnDefinition < Struct.new(:name, :type, :limit, :precision, :scale, :default, :null, :first, :after, :primary_key) #:nodoc: - def string_to_binary(value) - value - end def primary_key? primary_key || type.to_sym == :primary_key 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 5b25b26164..4b11ea795c 100644..100755 --- a/activerecord/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +++ b/activerecord/lib/active_record/connection_adapters/abstract_mysql_adapter.rb @@ -246,8 +246,8 @@ module ActiveRecord # QUOTING ================================================== def quote(value, column = nil) - if value.kind_of?(String) && column && column.type == :binary && column.class.respond_to?(:string_to_binary) - s = column.class.string_to_binary(value).unpack("H*")[0] + if value.kind_of?(String) && column && column.type == :binary + s = value.unpack("H*")[0] "x'#{s}'" elsif value.kind_of?(BigDecimal) value.to_s("F") @@ -469,7 +469,8 @@ module ActiveRecord sql = "SHOW FULL FIELDS FROM #{quote_table_name(table_name)}" execute_and_free(sql, 'SCHEMA') do |result| each_hash(result).map do |field| - new_column(field[:Field], field[:Default], field[:Type], field[:Null] == "YES", field[:Collation], field[:Extra]) + field_name = set_field_encoding(field[:Field]) + new_column(field_name, field[:Default], field[:Type], field[:Null] == "YES", field[:Collation], field[:Extra]) end end end diff --git a/activerecord/lib/active_record/connection_adapters/column.rb b/activerecord/lib/active_record/connection_adapters/column.rb index cc02b313e1..bccfa41ad1 100644 --- a/activerecord/lib/active_record/connection_adapters/column.rb +++ b/activerecord/lib/active_record/connection_adapters/column.rb @@ -119,17 +119,7 @@ module ActiveRecord type_cast(default) end - # Used to convert from Strings to BLOBs - def string_to_binary(value) - self.class.string_to_binary(value) - end - class << self - # Used to convert from Strings to BLOBs - def string_to_binary(value) - value - end - # Used to convert from BLOBs to Strings def binary_to_string(value) value diff --git a/activerecord/lib/active_record/connection_adapters/mysql2_adapter.rb b/activerecord/lib/active_record/connection_adapters/mysql2_adapter.rb index 28c7cff1cc..92796c996e 100644..100755 --- a/activerecord/lib/active_record/connection_adapters/mysql2_adapter.rb +++ b/activerecord/lib/active_record/connection_adapters/mysql2_adapter.rb @@ -269,6 +269,10 @@ module ActiveRecord def version @version ||= @connection.info[:version].scan(/^(\d+)\.(\d+)\.(\d+)/).flatten.map { |v| v.to_i } end + + def set_field_encoding field_name + field_name + end end end end diff --git a/activerecord/lib/active_record/connection_adapters/mysql_adapter.rb b/activerecord/lib/active_record/connection_adapters/mysql_adapter.rb index fbe6ecf5f1..15b5452850 100644..100755 --- a/activerecord/lib/active_record/connection_adapters/mysql_adapter.rb +++ b/activerecord/lib/active_record/connection_adapters/mysql_adapter.rb @@ -559,6 +559,14 @@ module ActiveRecord def version @version ||= @connection.server_info.scan(/^(\d+)\.(\d+)\.(\d+)/).flatten.map { |v| v.to_i } end + + def set_field_encoding field_name + field_name.force_encoding(client_encoding) + if internal_enc = Encoding.default_internal + field_name = field_name.encoding(internal_enc) + end + field_name + end end end end diff --git a/activerecord/lib/active_record/connection_adapters/postgresql/oid.rb b/activerecord/lib/active_record/connection_adapters/postgresql/oid.rb index 1be116ce10..58c6235059 100644 --- a/activerecord/lib/active_record/connection_adapters/postgresql/oid.rb +++ b/activerecord/lib/active_record/connection_adapters/postgresql/oid.rb @@ -6,10 +6,6 @@ module ActiveRecord module OID class Type def type; end - - def type_cast_for_write(value) - value - end end class Identity < Type @@ -224,6 +220,10 @@ module ActiveRecord end class Hstore < Type + def type_cast_for_write(value) + ConnectionAdapters::PostgreSQLColumn.hstore_to_string value + end + def type_cast(value) return if value.nil? diff --git a/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb b/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb index 342d1b1433..5b9453a579 100644 --- a/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb +++ b/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb @@ -129,6 +129,14 @@ module ActiveRecord end end + def type_cast_for_write(value) + if @oid_type.respond_to?(:type_cast_for_write) + @oid_type.type_cast_for_write(value) + else + super + end + end + def type_cast(value) return if value.nil? return super if encoded? diff --git a/activerecord/lib/active_record/connection_adapters/sqlite3_adapter.rb b/activerecord/lib/active_record/connection_adapters/sqlite3_adapter.rb index e1475416eb..df489a5b1f 100644 --- a/activerecord/lib/active_record/connection_adapters/sqlite3_adapter.rb +++ b/activerecord/lib/active_record/connection_adapters/sqlite3_adapter.rb @@ -226,8 +226,8 @@ module ActiveRecord # QUOTING ================================================== def quote(value, column = nil) - if value.kind_of?(String) && column && column.type == :binary && column.class.respond_to?(:string_to_binary) - s = column.class.string_to_binary(value).unpack("H*")[0] + if value.kind_of?(String) && column && column.type == :binary + s = value.unpack("H*")[0] "x'#{s}'" else super diff --git a/activerecord/test/cases/adapters/postgresql/hstore_test.rb b/activerecord/test/cases/adapters/postgresql/hstore_test.rb index e434b4861c..f61f196c71 100644 --- a/activerecord/test/cases/adapters/postgresql/hstore_test.rb +++ b/activerecord/test/cases/adapters/postgresql/hstore_test.rb @@ -70,6 +70,13 @@ class PostgresqlHstoreTest < ActiveRecord::TestCase Hstore.reset_column_information end + def test_cast_value_on_write + x = Hstore.new tags: {"bool" => true, "number" => 5} + assert_equal({"bool" => "true", "number" => "5"}, x.tags) + x.save + assert_equal({"bool" => "true", "number" => "5"}, x.reload.tags) + end + def test_type_cast_hstore assert @column diff --git a/activerecord/test/cases/base_test.rb b/activerecord/test/cases/base_test.rb index cd2b341826..c91cf89f6d 100644..100755 --- a/activerecord/test/cases/base_test.rb +++ b/activerecord/test/cases/base_test.rb @@ -584,12 +584,9 @@ class BasicsTest < ActiveRecord::TestCase assert_equal "changed", post.body end - unless current_adapter?(:MysqlAdapter) - def test_unicode_column_name - columns = Weird.columns_hash.keys - weird = Weird.create(:なまえ => 'たこ焼き仮面') - assert_equal 'たこ焼き仮面', weird.なまえ - end + def test_unicode_column_name + weird = Weird.create(:なまえ => 'たこ焼き仮面') + assert_equal 'たこ焼き仮面', weird.なまえ end def test_non_valid_identifier_column_name diff --git a/activerecord/test/cases/quoting_test.rb b/activerecord/test/cases/quoting_test.rb index 85fbe01416..44b2064110 100644 --- a/activerecord/test/cases/quoting_test.rb +++ b/activerecord/test/cases/quoting_test.rb @@ -184,25 +184,6 @@ module ActiveRecord assert_equal "'lo\\\\l'", @quoter.quote('lo\l', FakeColumn.new(:binary)) end - def test_quote_binary_with_string_to_binary - col = Class.new(FakeColumn) { - def string_to_binary(value) - 'foo' - end - }.new(:binary) - assert_equal "'foo'", @quoter.quote('lo\l', col) - end - - def test_quote_as_mb_chars_binary_column_with_string_to_binary - col = Class.new(FakeColumn) { - def string_to_binary(value) - 'foo' - end - }.new(:binary) - string = ActiveSupport::Multibyte::Chars.new('lo\l') - assert_equal "'foo'", @quoter.quote(string, col) - end - def test_string_with_crazy_column assert_equal "'lo\\\\l'", @quoter.quote('lo\l', FakeColumn.new(:foo)) end diff --git a/guides/source/asset_pipeline.md b/guides/source/asset_pipeline.md index 639a00817b..862742679c 100644 --- a/guides/source/asset_pipeline.md +++ b/guides/source/asset_pipeline.md @@ -905,7 +905,7 @@ Customizing the Pipeline ### CSS Compression There is currently one option for compressing CSS, YUI. The [YUI CSS -compressor]((http://yui.github.io/yuicompressor/css.html) provides +compressor](http://yui.github.io/yuicompressor/css.html) provides minification. The following line enables YUI compression, and requires the `yui-compressor` diff --git a/guides/source/engines.md b/guides/source/engines.md index a77be917a2..9106b6382d 100644 --- a/guides/source/engines.md +++ b/guides/source/engines.md @@ -525,6 +525,14 @@ First, the `author_name` text field needs to be added to the `app/views/blorgh/p </div> ``` +Next, we need to update our `Blorgh::PostController#post_params` method to permit the new form parameter: + +```ruby +def post_params + params.require(:post).permit(:title, :text, :author_name) +end +``` + The `Blorgh::Post` model should then have some code to convert the `author_name` field into an actual `User` object and associate it as that post's `author` before the post is saved. It will also need to have an `attr_accessor` setup for this field so that the setter and getter methods are defined for it. To do all this, you'll need to add the `attr_accessor` for `author_name`, the association for the author and the `before_save` call into `app/models/blorgh/post.rb`. The `author` association will be hard-coded to the `User` class for the time being. diff --git a/guides/source/getting_started.md b/guides/source/getting_started.md index acfbf24f12..784a61adc1 100644 --- a/guides/source/getting_started.md +++ b/guides/source/getting_started.md @@ -641,7 +641,7 @@ private ``` See the `permit`? It allows us to accept both `title` and `text` in this -action. With this change, you should finally be able to create new `Post`s. +action. With this change, you should finally be able to create new posts. Visit <http://localhost:3000/posts/new> and give it a try!  |