It appears that in Rails 3.2.21, saving a serialized hash fails to save a value that comes from one specifc NumberHelper, helper.number_with_delimiter
In a Rails 3.2 app, in model Foo I have:
serialize :stuff, Hash
In the console:
f = Foo.create
f.stuff = { a: "aaaa", b: 1111, c: helper.number_with_delimiter(123456) }
=> {:a=>"aaaa", :b=>1111, :c=>"123,456"} # so far so good
f.save!
f.stuff
=> {:a=>"aaaa", :b=>1111, :c=>123456} # c should be a STRING
It DOES work correctly with helper.number_to_currency().
And it works if I set c: String.new(helper.number_with_delimiter(123456)).
This is a Rails bug, or am I doing something wrong?
Yes, this is a Rails (ActiveSupport) bug that was eventually fixed in Rails 4.2.1. From the 4.2.1 release notes:
Fixed a roundtrip problem with AS::SafeBuffer where primitive-like strings will be dumped as primitives
When you use helper.number_with_delimiter, the resulting object looks and behaves like a String, but in reality it is an ActiveSupport::SafeBuffer.
helper.number_with_delimiter(123456).class # => ActiveSupport::SafeBuffer < String
When you use:
serialize :stuff, Hash
That means behind the scenes Rails is using YAML format to save the data to the database. There was a bug in SafeBuffer that caused SafeBuffers like "123" to be mistakenly converted to integers (i.e. 123) instead of remaining strings when saving and loading to/from YAML.
Again, this is now fixed as of Rails 4.2.1. You can see the fix here:
https://github.com/rails/rails/commit/debe7aedda3665702d1f99a3ffb4a123a6c44e9c
Related
I am upgrading my Rails application from v3.2 to v4.0. In my User model I have a JSON coded Store:
store :settings, accessors: [
:confirmed,
:receive_marketing_emails,
:receive_reply_emails
], coder: JSON
This works as expected, serializing User.settings and providing accessors.
However when I move to Rails 4.0 the Store stops working. I get the following error when I attempt to look up any User:
JSON::ParserError: 795: unexpected token at '---
:confirmed,
:receive_marketing_emails,
:receive_reply_emails
'
Can anyone provide any insight?
There is this statement in the Rails Upgrade Guide:
Rails 4.0 has changed ActiveModel::Serializers::JSON.include_root_in_json default value to false. Now, Active Model Serializers and Active Record objects have the same default behavior.
I'd suggest that when you are accessing a User instance, the json field cannot be deserialized since it expects no root, while the serialized data has it.
To revert to Rails 3.2 behaviour, put this in your config/initializers/wrap_parameters.rb:
ActiveSupport.on_load(:active_record) do
self.include_root_in_json = true
end
Per this question's answer:
Earlier (ActiveRecord 3.2.8) the data is stored in database is in YAML format, and it was working with "coder: JSON", which is not case in ActiveRecord 4.2.4.
So even though you would specify coder: JSON, the data was being serialized to YAML, and not JSON. Strange.
To answer my own question, in Rails 4.0 I just had to change coder: JSON to coder: YAML.
anyone seen this array error before?
I have a helper method that returns an array. In development mode on my laptop it returns the array in an expected format:
var fire =
[[1349083353000, 8.860000000000582], [1349085153000, 19.779999999999745],
[1349086953000, 20.289999999999964], [1349088753000, 29.850000000000364],
[1349090553000, 3.7999999999992724]];
BUT same code in production returns a strange array format:
var fire = 135175422800015.5135175602800020.0135175782800018.99135175962800012.33135176142800019.13135176322800029.55135176502800020.13135176682800077.34
I have tried checking the output in rails console on either machine and the production output the same weird array format. I have created a new array from within rails console on production and it works as expected to output the correct format of array.
Anyone seen this bit of weirdness?
Rails version:3.2.8
Ruby Version:1.9.3p-125
You're probably developing on Ruby 1.9 and deploying on Ruby 1.8. The default behaviors for treating arrays are different.
In Ruby 1.8 array.to_s is equivalent to array.join('').
In Ruby 1.9 array.to_s is equivalent to array.inspect.
If you want the proper behavior on both, and you're using JavaScript, you might want to render it as JSON using array.to_json instead.
I have the following structure :
a = { 'x' => [1,2,3] }
In Rails 3.0 with ruby 1.8, the conversion to JSON works as expected :
a.to_json
=> "{\"x\":[1,2,3]}"
In Rails 3.1 with ruby 1.9.3p125, the array is transformed into a hash :
a.to_json
=> "{\"x\":{\"1\":null,\"2\":null,\"3\":null}}"
I can't find any documentation explaining the difference in behaviour between the two versions, nor any way to preserve the expected output in Rails 3.1. Any clues ?
The problem is actually related to one of the gems installed on the Gemfile, which returns an incorrect result for to_json calls.
Thanks for the help.
I'm trying to roundtrip encode/decode plain strings in json, but I'm getting an error.
In rails 2.3. w/ ruby 1.8.6, it used to work.
>> puts ActiveSupport::JSON.decode("abc".to_json)
abc
=> nil
In rails 3.1beta1 w/ ruby 1.9.2, it raises an error.
ruby-1.9.2-p180 :001 > puts ActiveSupport::JSON.decode("abc".to_json)
MultiJson::DecodeError: 706: unexpected token at '"abc"'
from /home/stevenh/.rvm/rubies/ruby-1.9.2-p180/lib/ruby/1.9.1/json/common.rb:147:in `parse'
from /home/stevenh/.rvm/rubies/ruby-1.9.2-p180/lib/ruby/1.9.1/json/common.rb:147:in `parse'
from /home/stevenh/.rvm/gems/ruby-1.9.2-p180/gems/multi_json-1.0.1/lib/multi_json/engines/json_gem.rb:13:in `decode'
[...]
This is pretty much the same question discussed at nil.to_json cannot be parsed back to nil?
But nil used to work in 2.3/1.8.7 as well.
puts ActiveSupport::JSON.decode(nil.to_json)
nil
Is this the new normal?
This change occurred with the switch from ActiveSupport's JSON backend to MultiJson that was included in Rails 3.1.0.rc1. Per the MultiJson project team, the current behavior is correct and the previous implementation was faulty due to RFC4627's specification of the JSON grammar:
2. JSON Grammar
A JSON text is a sequence of tokens. The set of tokens includes six
structural characters, strings, numbers, and three literal names.
A JSON text is a serialized object or array.
JSON-text = object / array
As neither "abc" nor "/"abc/"" are serialized objects or arrays, an error when attempting to decode them is appropriate.
The diagrams from the JSON website reinforce this specification.
That being said, this would seem to imply a bug in the to_json implementation that results in:
ruby-1.9.2-p180 :001 > "abc".to_json
=> "\"abc\""
Yes, what is happening in Rails3 is the new normal. The changes you illustrate seem like a reflection of a maturing framework.
Methods named "encode" & "decode" should be expected to be perfectly compliant with the JSON spec, and inverses of one another.
String#to_json, on the other hand is a behavior-ish type of method that functions as a convenience for building more complex JSON objects presumably used internally (within ActiveSupport) when Array#to_json or Hash#to_json encounter a String value as one of their consituent elements.
If you need to restore that behavior follow these steps, i.e.
# in your Gemfile
gem 'yajl-ruby'
# in your application.rb
require 'yajl/json_gem'
After those steps:
Loading development environment (Rails 3.2.8)
[1] pry(main)> puts ActiveSupport::JSON.decode("abc".to_json)
abc
=> nil
[2] pry(main)> puts ActiveSupport::JSON.decode(nil.to_json)
=> nil
I am using NetBeans to create my first Ruby on Rails application. Is there a way by which I can view all of the properties of a model? Should I just be looking in the database?
I just use db/schema.rb - seems to work fine for me.
You can use the annotate gem for this - it will add comments to the top of each model indicating its properties.
You could call Model.attributes in Rails' console. This gives a hash with all attributes.
Be careful when using this inside your real code as it always recreates the hash and is therefore pretty expensive.
Just type your model name on the rails console then press Enter.
rails c # start your rails console
User
=> User(id: integer, email: string, password_digest: string...)
In case anyone is viewing this and is using a newer version of Rails, you can just call Model in the console. (I'm on Rails 3.2.1 and Ruby 1.9.2p290.)
In fact, calling Model.attributes in this case does not work.
A nice little tool that I use is from MySQL. It is called MySQL Administrator.
It lets me validate that the db (development/test/production), the tables for the db, and finally the columns(attributes).
Model.attributes #=> {'name' => 'foo', 'desc' => 'bar'}
P.S. www.railsbrain.com - use this.