Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Improve json conversion with tests and support for older Rails 3.x #787

Conversation

cheremukhin23
Copy link
Contributor

@cheremukhin23 cheremukhin23 commented Mar 31, 2017

  • Add error handling when unable to parse json
  • Add tests to ensure json_safe_and_pretty handles hashes and strings

This change is Reviewable

@coveralls
Copy link

coveralls commented Mar 31, 2017

Coverage Status

Coverage increased (+0.003%) to 97.925% when pulling 5867246 on cheremukhin23:improve-json-safe-and-pretty into 5954e36 on shakacode:master.

@coveralls
Copy link

coveralls commented Apr 1, 2017

Coverage Status

Coverage increased (+0.01%) to 97.935% when pulling a3ef532 on cheremukhin23:improve-json-safe-and-pretty into 5954e36 on shakacode:master.

@justin808
Copy link
Member

Looking great!


Reviewed 1 of 2 files at r1, 1 of 1 files at r2.
Review status: all files reviewed at latest revision, 4 unresolved discussions.


app/helpers/react_on_rails_helper.rb, line 223 at r2 (raw file):

  end

  def json_safe_and_pretty(hash_or_string)

Can we throw here if the value passed is not a hash or a string? What else could the value be?


app/helpers/react_on_rails_helper.rb, line 231 at r2 (raw file):

      escape_json(hash_value.to_json)
    end
  rescue JSON::ParserError => e

Can we move this catch block around the JSON.parse above?

we can do something like:

  hash_value = if hash_or_string.is_a?(String) 
                          begin
                              JSON.parse(hash_or_string)
                           rescue JSON::ParserError => e
                               raise e, %(Cannot parse #{hash_or_string} \n Backtrace: #{e.backtrace.join("\n")})
                          else
                              hash_or_string
                          end  

app/helpers/react_on_rails_helper.rb, line 242 at r2 (raw file):

  end

  def old_json_escape(json)

Can you provide a comment with a link on to the github source of this?


spec/dummy/spec/helpers/react_on_rails_helper_spec.rb, line 40 at r2 (raw file):

      expect(escaped_json).to eq(hash_sanitized)
    end
  end

Can we add a couple tests that confirm the exceptions:

  1. non-hash, non-string passed
  2. non parseable string in development mode

Also, we're never testing the part where we check we're in development mode.

I'd try to mock/stub out the Rails.env for that test.

# RSpec version
it 'tests my code' do
  allow(Rails).to receive(:env).and_return(ActiveSupport::StringInquirer.new('development'))
  # test code
end

Some options from Google


Comments from Reviewable

@justin808
Copy link
Member

See note below. I might just release a temp patch on this.


Review status: all files reviewed at latest revision, 5 unresolved discussions.


app/helpers/react_on_rails_helper.rb, line 224 at r2 (raw file):

  def json_safe_and_pretty(hash_or_string)
    hash_value = hash_or_string.is_a?(String) ? JSON.parse(hash_or_string) : hash_or_string

djudji [1:57 AM]
OK, so this is the thing, the code brakes at AppointmentsList component, after the update. It gives an appointments.map is not a function error, which means that it can not iterate over the Object type (edited)

[1:59]
@justin any recommendations?

djudji [3:31 AM]
could it be a new way of passing data from Rails to React (as I am testing more and more, it looks like props is not getting the right values from a controller)?

djudji [3:53 AM]
it hangs inside function render(el, railsContext) in clientStartup.js

[3:55]
this is how I am sending the data to a React component
react_component 'Appointments', props: {appointments: @appointments}

[3:56]
and on "the other side" I get
Object {appointments: "#<Appointment::ActiveRecord_Relation:0x007f972440cb90>"}
instead of an array of Objects, like before updating to 6.9.1 (edited)

justin [8:16 AM]
Dev or production. Please try both.

djudji [9:49 AM]
Currently on dev. Will try it in production again (first app didn't work because I haven't set a new version for react_on_rails in package.json)

OK, this is a bit strange.

  1. I cloned non-updated app
  2. I did upgrade to react_on_rails 6.9.1
  3. Created a new heroku app and pushed the upgraded app to Heroku.

Now everything is working fine in production, but in dev I still have the same error.

This is the URL -> https://calendar-react-on-rails.herokuapp.com/

I can confirm that both of the apps work when pushed to production.

This is the first URL -> https://calendar-railsreact.herokuapp.com/ (edited

the error is in the conversion to the pretty JSON… for development mode.

   if Rails.env.development?
     # TODO: for json_safe_and_pretty
     # 1. Add test
     # 2. Add error handler if cannot parse the string with nice message
     # 3. Consider checking that if not a string then a Hash
     hash_value = hash_or_string.is_a?(String) ? JSON.parse(hash_or_string) : hash_or_string
     ERB::Util.json_escape(JSON.pretty_generate(hash_value))
   else
     ERB::Util.json_escape(hash_or_string.to_json)
   end
 end

Before, we used to call:

    props.is_a?(String) ? json_escape(props) : props.to_json
  end```


So I think if a Hash is passed, rather than a string, and we want to pretty print, then we’d have to go:

1. Hash => to_json (converts active record objects) => String
2. String => Hash
3. Then call `ERB::Util.json_escape(JSON.pretty_generate(hash_value))`

This could be a little slow.

1. Wondering if this should be optional, in `config/initializers/react_on_rails.rb`
2. Another option is skip pretty printing completely (but then should make an option).

---


*Comments from [Reviewable](https://reviewable.io:443/reviews/shakacode/react_on_rails/787#-:-KggFA9_7z0FTL11MGXB:b-u1x6lu)*
<!-- Sent from Reviewable.io -->

@justin808
Copy link
Member

Note #789 is removing the pretty formatting.

We can add it back in...

@justin808
Copy link
Member

@cheremukhin23 I thought more about the pretty formatting of json.

Let's add a configuration flag for this, since it tends to break...

Default is false.

# Pretty printing props looks nice when you view the page source. However, if you have a large
# amount of props data, the page rendering can be a little slower.
config.pretty_print_props_in_development = false

@justin808
Copy link
Member

See #791. I fixed another critical bug...

[1] (pry) #<#<Class:0x007f84e5bd19f8>>: 0> puts hash_or_string.to_json
"{\"comments\":[{\"id\":9,\"author\":\"xxx\",\"text\":\"xxxxxx\",\"created_at\":\"2017-01-11T08:14:10.296Z\",\"updated_at\":\"2017-01-11T08:14:10.296Z\"},

[2] (pry) #<Class:0x007f84e5bd19f8>>: 0> puts hash_or_string
{"comments":[{"id":9,"author":"xxx","text":"xxxxxx","created_at":"2017-01-11T08:14:10.296Z","updated_at":"2017-01-11T08:14:10.296Z"},

@justin808
Copy link
Member

See #799

@cheremukhin23
Copy link
Contributor Author

Review status: 0 of 2 files reviewed at latest revision, 5 unresolved discussions.


app/helpers/react_on_rails_helper.rb, line 223 at r2 (raw file):

Previously, justin808 (Justin Gordon) wrote…

Can we throw here if the value passed is not a hash or a string? What else could the value be?

We discard this code


app/helpers/react_on_rails_helper.rb, line 224 at r2 (raw file):

Previously, justin808 (Justin Gordon) wrote…

djudji [1:57 AM]
OK, so this is the thing, the code brakes at AppointmentsList component, after the update. It gives an appointments.map is not a function error, which means that it can not iterate over the Object type (edited)

[1:59]
@justin any recommendations?

djudji [3:31 AM]
could it be a new way of passing data from Rails to React (as I am testing more and more, it looks like props is not getting the right values from a controller)?

djudji [3:53 AM]
it hangs inside function render(el, railsContext) in clientStartup.js

[3:55]
this is how I am sending the data to a React component
react_component 'Appointments', props: {appointments: @appointments}

[3:56]
and on "the other side" I get
Object {appointments: "#<Appointment::ActiveRecord_Relation:0x007f972440cb90>"}
instead of an array of Objects, like before updating to 6.9.1 (edited)

justin [8:16 AM]
Dev or production. Please try both.

djudji [9:49 AM]
Currently on dev. Will try it in production again (first app didn't work because I haven't set a new version for react_on_rails in package.json)

OK, this is a bit strange.

  1. I cloned non-updated app
  2. I did upgrade to react_on_rails 6.9.1
  3. Created a new heroku app and pushed the upgraded app to Heroku.

Now everything is working fine in production, but in dev I still have the same error.

This is the URL -> https://calendar-react-on-rails.herokuapp.com/

I can confirm that both of the apps work when pushed to production.

This is the first URL -> https://calendar-railsreact.herokuapp.com/ (edited

the error is in the conversion to the pretty JSON… for development mode.

   if Rails.env.development?
     # TODO: for json_safe_and_pretty
     # 1. Add test
     # 2. Add error handler if cannot parse the string with nice message
     # 3. Consider checking that if not a string then a Hash
     hash_value = hash_or_string.is_a?(String) ? JSON.parse(hash_or_string) : hash_or_string
     ERB::Util.json_escape(JSON.pretty_generate(hash_value))
   else
     ERB::Util.json_escape(hash_or_string.to_json)
   end
 end

Before, we used to call:

    props.is_a?(String) ? json_escape(props) : props.to_json
  end```


So I think if a Hash is passed, rather than a string, and we want to pretty print, then we’d have to go:

1. Hash => to_json (converts active record objects) => String
2. String => Hash
3. Then call `ERB::Util.json_escape(JSON.pretty_generate(hash_value))`

This could be a little slow.

1. Wondering if this should be optional, in `config/initializers/react_on_rails.rb`
2. Another option is skip pretty printing completely (but then should make an option).
</blockquote></details>

currently decided not to use pretty generate

---

*[app/helpers/react_on_rails_helper.rb, line 231 at r2](https://reviewable.io:443/reviews/shakacode/react_on_rails/787#-KgcggrDdvDqTLt3uR8q:-KhSNfG5p3IgHg_wp0bx:b-vjole3) ([raw file](https://github.com/shakacode/react_on_rails/blob/a3ef532d26039dc87d3032142a3171a6d26b2f3a/app/helpers/react_on_rails_helper.rb#L231)):*
<details><summary><i>Previously, justin808 (Justin Gordon) wrote…</i></summary><blockquote>

Can we move this catch block around the JSON.parse above?

we can do something like:

```ruby
  hash_value = if hash_or_string.is_a?(String) 
                          begin
                              JSON.parse(hash_or_string)
                           rescue JSON::ParserError => e
                               raise e, %(Cannot parse #{hash_or_string} \n Backtrace: #{e.backtrace.join("\n")})
                          else
                              hash_or_string
                          end  

discarded code


app/helpers/react_on_rails_helper.rb, line 242 at r2 (raw file):

Previously, justin808 (Justin Gordon) wrote…

Can you provide a comment with a link on to the github source of this?

added link


spec/dummy/spec/helpers/react_on_rails_helper_spec.rb, line 40 at r2 (raw file):

Previously, justin808 (Justin Gordon) wrote…

Can we add a couple tests that confirm the exceptions:

  1. non-hash, non-string passed
  2. non parseable string in development mode

Also, we're never testing the part where we check we're in development mode.

I'd try to mock/stub out the Rails.env for that test.

# RSpec version
it 'tests my code' do
  allow(Rails).to receive(:env).and_return(ActiveSupport::StringInquirer.new('development'))
  # test code
end

Some options from Google

added test for arguments


Comments from Reviewable

@justin808
Copy link
Member

We need to fix this deprecation for React.

====> React On Rails: Checking app/assets/webpack for outdated/missing bundles
You're running an old version of PhantomJS, update to >= 2.1.1 for a better experience.
  the hello world example works (FAILED - 1)
Failures:
  1) Hello World the hello world example works
     Failure/Error: visit "/hello_world"
     
     Capybara::Poltergeist::JavascriptError:
       One or more errors were raised in the Javascript code on the page. If you don't care about these errors, you can ignore them by setting js_errors: false in your Poltergeist configuration (see documentation for details).
     
       Warning: Accessing PropTypes via the main React package is deprecated. Use the prop-types package from npm instead.
       Warning: Accessing PropTypes via the main React package is deprecated. Use the prop-types package from npm instead.
           at :36 in printWarning
     # /home/travis/.rvm/gems/ruby-2.2.6/gems/poltergeist-1.13.0/lib/capybara/poltergeist/browser.rb:376:in `command'
     # /home/travis/.rvm/gems/ruby-2.2.6/gems/poltergeist-1.13.0/lib/capybara/poltergeist/browser.rb:35:in `visit'
     # /home/travis/.rvm/gems/ruby-2.2.6/gems/poltergeist-1.13.0/lib/capybara/poltergeist/driver.rb:97:in `visit'
     # /home/travis/.rvm/gems/ruby-2.2.6/gems/capybara-2.12.1/lib/capybara/session.rb:252:in `visit'
     # /home/travis/.rvm/gems/ruby-2.2.6/gems/capybara-2.12.1/lib/capybara/dsl.rb:52:in `block (2 levels) in <module:DSL>'
     # ./spec/features/hello_world_spec.rb:5:in `block (2 levels) in <top (required)>'
     # /home/travis/.rvm/gems/ruby-2.2.6/gems/rspec-retry-0.5.3/lib/rspec/retry.rb:112:in `block in run'
     # /home/travis/.rvm/gems/ruby-2.2.6/gems/rspec-retry-0.5.3/lib/rspec/retry.rb:101:in `loop'
     # /home/travis/.rvm/gems/ruby-2.2.6/gems/rspec-retry-0.5.3/lib/rspec/retry.rb:101:in `run'
     # /home/travis/.rvm/gems/ruby-2.2.6/gems/rspec-retry-0.5.3/lib/rspec_ext/rspec_ext.rb:12:in `run_with_retry'
     # /home/travis/.rvm/gems/ruby-2.2.6/gems/rspec-retry-0.5.3/lib/rspec/retry.rb:30:in `block (2 levels) in setup'
Finished in 2.4 seconds (files took 2.58 seconds to load)
1 example, 1 failure

@justin808
Copy link
Member

Looking good:

  1. Few comments.
  2. Need to pass CI. That could be a separate PR on master
  3. Need a CHANGELOG.md entry.

Reviewed 2 of 2 files at r3.
Review status: all files reviewed at latest revision, 1 unresolved discussion, some commit checks broke.


app/helpers/react_on_rails_helper.rb, line 234 at r3 (raw file):

  def escape_json(json)
    return old_json_escape(json) unless Rails::VERSION::STRING >= "4"

I think this not right. What if the Rails version is "10.0".

Please google for a proper version comparator.

Something like this (you creating the rails_version_less_than

 return old_json_escape(json) if rails_version_less_than(4.0)

Comments from Reviewable

@justin808
Copy link
Member

@cheremukhin23 See comment: #799 (comment)

@justin808
Copy link
Member

@cheremukhin23 @squadette Maybe I should merge this one and let's add the feature in a new PR?

@justin808
Copy link
Member

please rebase on master and that should fix the CI, @cheremukhin23

@justin808 justin808 changed the title Improve json safe and pretty Improve json conversion with tests and support for older Rails 3.x Apr 13, 2017
…into improve-json-safe-and-pretty

# Conflicts:
#	app/helpers/react_on_rails_helper.rb
@coveralls
Copy link

Coverage Status

Coverage increased (+0.02%) to 97.997% when pulling 78a1c3c on cheremukhin23:improve-json-safe-and-pretty into d5d579e on shakacode:master.

1 similar comment
@coveralls
Copy link

Coverage Status

Coverage increased (+0.02%) to 97.997% when pulling 78a1c3c on cheremukhin23:improve-json-safe-and-pretty into d5d579e on shakacode:master.

@cheremukhin23
Copy link
Contributor Author

Review status: 1 of 3 files reviewed at latest revision, 1 unresolved discussion.


app/helpers/react_on_rails_helper.rb, line 234 at r3 (raw file):

Previously, justin808 (Justin Gordon) wrote…

I think this not right. What if the Rails version is "10.0".

Please google for a proper version comparator.

Something like this (you creating the rails_version_less_than

 return old_json_escape(json) if rails_version_less_than(4.0)

Used Gem::Version to compare versions


Comments from Reviewable

@coveralls
Copy link

coveralls commented Apr 13, 2017

Coverage Status

Coverage increased (+0.02%) to 97.997% when pulling 19722db on cheremukhin23:improve-json-safe-and-pretty into d5d579e on shakacode:master.

@justin808
Copy link
Member

Very close. But missing tests on part of the PR.


Reviewed 1 of 1 files at r5, 1 of 1 files at r6.
Review status: all files reviewed at latest revision, 2 unresolved discussions, some commit checks failed.


app/helpers/react_on_rails_helper.rb, line 251 at r6 (raw file):

    json_escape = { "&" => '\u0026', ">" => '\u003e', "<" => '\u003c', "\u2028" => '\u2028', "\u2029" => '\u2029' }
    json_escape_regexp = /[\u2028\u2029&><]/u
    json.to_s.gsub(json_escape_regexp, json_escape)

This code is not tested. We need a test to confirm this method works as well as the method rails_version_less_than.

Please add a couple simple tests for rails_version_less_than with cases "3.2", "3", "4.2", "10.0".


Comments from Reviewable

@justin808
Copy link
Member

@cheremukhin23 Please let me know if you can finish this. If you don't have time, I need to find an alternate resource.

@squadette, any chance that you can help with this one?

@justin808
Copy link
Member

@Ynote, is there chance that you can give us a hand with this one?

@@ -224,8 +224,33 @@ def server_render_js(js_expression, options = {})
# rubocop:enable Style/RaiseArgs
end

def json_safe_and_pretty(hash_or_string)
unless hash_or_string.class.in?([Hash, String])
raise "#{hash_or_string.class} is unsupported argument class for this method"
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would name the types that are accepted by the method in this error.

@Ynote
Copy link
Contributor

Ynote commented Apr 18, 2017

Hi,

I can help on the PR. @cheremukhin23, can you give me permission on the PR so I can fetch the branch and add the missing tests?

@justin808
Copy link
Member

@Ynote @cheremukhin23 You can also pull his changes into your own fork and make a new branch.

@squadette would like us to put back in JSON props as pretty. I'm ok with that either in this or a different PR, but I won't accept any PR without full test coverage and documentation changes.

@justin808
Copy link
Member

See #812.

@justin808 justin808 closed this Apr 21, 2017
justin808 pushed a commit that referenced this pull request Apr 23, 2017
…ails older than 4.1 (#812)

* Improve json_safe_and_pretty method to handle parse error
* Add tests to json_safe_and_pretty method
* Add old json escape method for Rails versions less than 4
* Add json safe and pretty argument class test
* Add rails version less than method
* Add tests for json encoding helper methods
* Move rails_version_less_than method into Utils module
* Extract json escaping logic into JsonOutput class
* Remove "or equal" logic from rails_version_less_than util method
* Use monkey patch json escape from Rails 4.2 instead of Rails 4
* Memoize result for static method rails_version_less_than
* Update json escaping method into class methods
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants