This project is archived and is in readonly mode.
Correct output from ActiveModel::Errors to_json
-
Samuel Kadolph
The solution is to override the ActiveModel::Errors#as_json method to give the full_messages array to be converted to JSON. Patch is attached.
-
Samuel Kadolph
Complete patch is attached. (Sorry, new to the whole patching rails thing.)
-
José Valim
- Milestone cleared.
- Assigned user set to José Valim
The patch looks great, but it need tests to ensure we won't have a regression later.
-
Neeraj Singh
Trying to create a test for this one but running into stack level too deep issue.
Hopefully I'll have a test patch soon. :-)
-
Samuel Kadolph
I've been looking into writing a test case for this but I have to get the tests for rails going first which hasn't been easy on Windows and our only other Unix server with ruby 1.8.7 is for production and I won't be installing the oodles of gems that rails dev requires.
That aside, I did notice there is no test case for ActiveModel::Errors#to_xml. So it would be beneficial to write a case for that as well.
-
José Valim
Neeraj, I think it's expected that you run into StackLevelTooDeep before the patch is applied. :) It means your test is correct!
-
Neeraj Singh
- Tag changed from active model, active_model, errors, json, to_json to active model, active_model, errors, json, rails3, to_json
- State changed from new to open
There are couple of things going on which is making me pause and think.
-
in the test if I do topic.errors.to_json then it blows up saying to_json is not defined which does not make sense since active_model requires active_support which in turn requires json. So all objects should have to_json. I don't fully understand how autoload works so I need to learn that.
-
if I explicitly say require active_support/json to bring to_json then I get "stack level too deep" even with the fix in.
I am looking into it. expect some delays :-)
-
José Valim
JSON is autoloaded, but the to_json method is only added after you load it. So you need to explicitly require the json file (in tests).
About the stack level too deep error, could you please paste the strack trace here (not necessarily the whole backtrace ;))?
-
Neeraj Singh
test requires 'cases/helper'. helper in turn requires active_model which in turn requires active_support.
JSON is eagerly autoloaded in active_support. json.rb in turn requires encoding. So I fail to understand why to_json will be missing. Sorry for being so thick.
eager_autoload do autoload :JSON end require 'active_support/json/decoding' require 'active_support/json/encoding' -
Neeraj Singh
I added following line to test/cases/validations/presence_validation_test.rb
require "active_support/json/encoding" # added last three tests test 'accepts array arguments' do Topic.validates_presence_of %w(title content) t = Topic.new assert t.invalid? assert_equal ["can't be blank"], t.errors[:title] assert_equal ["can't be blank"], t.errors[:content] assert_match %r{<error>Title can't be blank</error>}, t.errors.to_xml assert_match %r{<error>Content can't be blank</error>}, t.errors.to_xml assert_nothing_raised { t.errors.to_json } endThis is the exception I am getting in its entirety
$ ruby -Itest test/cases/validations/presence_validation_test.rb -n /test_accepts_array_arguments/ Loaded suite test/cases/validations/presence_validation_test Started F Finished in 0.048406 seconds. 1) Failure: test_accepts_array_arguments(PresenceValidationTest) [test/cases/validations/presence_validation_test.rb:44:in `test_accepts_array_arguments' /Users/nsingh/dev/working/rails_tickets/r_4890/vendor/bundler/gems/rails-16a5e918a06649ffac24fd5873b875daf66212ad-master/activesupport/lib/active_support/testing/setup_and_teardown.rb:67:in `__send__' /Users/nsingh/dev/working/rails_tickets/r_4890/vendor/bundler/gems/rails-16a5e918a06649ffac24fd5873b875daf66212ad-master/activesupport/lib/active_support/testing/setup_and_teardown.rb:67:in `run' /Users/nsingh/dev/working/rails_tickets/r_4890/vendor/bundler/gems/rails-16a5e918a06649ffac24fd5873b875daf66212ad-master/activesupport/lib/active_support/callbacks.rb:408:in `_run_setup_callbacks' /Users/nsingh/dev/working/rails_tickets/r_4890/vendor/bundler/gems/rails-16a5e918a06649ffac24fd5873b875daf66212ad-master/activesupport/lib/active_support/testing/setup_and_teardown.rb:65:in `run']: Exception raised: Class: <SystemStackError> Message: <"stack level too deep"> ---Backtrace--- test/cases/validations/presence_validation_test.rb:44:in `to_json' test/cases/validations/presence_validation_test.rb:44:in `test_accepts_array_arguments' test/cases/validations/presence_validation_test.rb:44:in `test_accepts_array_arguments' /Users/nsingh/dev/working/rails_tickets/r_4890/vendor/bundler/gems/rails-16a5e918a06649ffac24fd5873b875daf66212ad-master/activesupport/lib/active_support/testing/setup_and_teardown.rb:67:in `__send__' /Users/nsingh/dev/working/rails_tickets/r_4890/vendor/bundler/gems/rails-16a5e918a06649ffac24fd5873b875daf66212ad-master/activesupport/lib/active_support/testing/setup_and_teardown.rb:67:in `run' /Users/nsingh/dev/working/rails_tickets/r_4890/vendor/bundler/gems/rails-16a5e918a06649ffac24fd5873b875daf66212ad-master/activesupport/lib/active_support/callbacks.rb:408:in `_run_setup_callbacks' /Users/nsingh/dev/working/rails_tickets/r_4890/vendor/bundler/gems/rails-16a5e918a06649ffac24fd5873b875daf66212ad-master/activesupport/lib/active_support/testing/setup_and_teardown.rb:65:in `run' --------------- 1 tests, 6 assertions, 1 failures, 0 errors -
José Valim
- Importance changed from to Low
Ok, I went deep down this problem and it turned out to be the JSON gem overwriting the to_json implementation for all core classes so Rails implementation was never used. The gem implementation does not work with hash inheritance, making ActiveSupport::OrderedHash fail when serialized to_json (and consequently ActiveModel::Errors). Patch is coming soon.
-
Repository
- State changed from open to resolved
(from [7bd85a8fc2d216a5e2b1d0380df572f782a54d1c]) Work around the fact the JSON gem was overwriting to_json implementation for all Ruby core classes.
This is required because the JSON gem is incompatible with Rails behavior and was not allowing ActiveModel::Errors to be serialized.
So we need to ensure Rails implementation is the one triggered. [#4890 Correct output from ActiveModel::Errors to_json state:resolved]
http://github.com/rails/rails/commit/7bd85a8fc2d216a5e2b1d0380df572...
