lundi 14 novembre 2016

Rails render_to_string using wrong format

I am encountering a problem with render_to_string using Rails 3.2.18 in which the function is trying to render the wrong view format despite its :formats option being correctly set (so for example rendering the kml view when :formats is set to text).


TL-DR version :

If I call render_to_string('foos/bar', formats: 'text', layout: false) and then render_to_string('foos/bar', formats: 'json', layout: false), the later renders bar.text instead of bar.json


Long version :

I have a FoosControler that uses render_to_text when its bar action is called. bar can respond to three formats : text, json and kml. Under my views, I have the three corresponding files bar.text.erb, bar.json.erb and bar.kml.erb. I also have three different tests, in which the controller is instantiated and the output of bar is tested for the different formats (so I am calling FoosControler.new.bar(format)).

If I run each of those tests independently, I have no problems at all. So :

render_to_string('foos/bar', formats: 'text', layout: false)
# => renders bar.text.erb


render_to_string('foos/bar', formats: 'json', layout: false)
# => renders bar.json.erb


render_to_string('foos/bar', formats: 'kml', layout: false)
# => renders bar.kml.erb

The problems start if I have more than one of these in my test suite. What happens is the following :

render_to_string('foos/bar', formats: 'json', layout: false)
# => renders bar.json.erb
render_to_string('foos/bar', formats: 'text', layout: false)
# => renders bar.text.erb
render_to_string('foos/bar', formats: 'json', layout: false)
# => renders bar.text.erb instead of bar.json.erb !

From the moment I rendered bar.text.erb, any call to render_to_string with the json format renders bar.text.erb instead of bar.json.erb like it is supposed to.

The same happens between kml and txt :

render_to_string('foos/bar', formats: 'text', layout: false)
# => renders bar.text.erb
render_to_string('foos/bar', formats: 'kml', layout: false)
# => renders bar.kml.erb
render_to_string('foos/bar', formats: 'text', layout: false)
# => renders bar.kml.erb instead of bar.text.erb !

I can't seem to understand why this problem happens, as the problem isn't linked to the views - they all exist and can be rendered as shown before. Even stranger, everything works if I force the format in the render instead of using the :format parameter :

render_to_string('foos/bar.text', layout: false)
# => renders bar.text.erb
render_to_string('foos/bar.kml', layout: false)
# => renders bar.kml.erb
render_to_string('foos/bar.text', layout: false)
# => renders bar.text.erb like it is supposed to

A few other precisions :
- It doesn't matter whether I use formats: '<format>' or formats: ['<format>']
- The problem happens regardless of whether I use the different render_to_string inside the same controller using a breakpoint or whether I simply call the sequence of FoosController.new.bar(format) in the test, so the following two give the same result :

FoosController.new.bar
    render_to_string('foos/bar', formats: 'kml', layout: false)
    # => renders bar.kml.erb
    render_to_string('foos/bar', formats: 'text', layout: false)
    # => renders bar.kml.erb instead of bar.text.erb !


FoosController.new.bar('kml')
# => renders bar.kml.erb
FoosController.new.bar('text')
# => renders bar.kml.erb instead of bar.text.erb !

Any idea what can cause this unwanted behavior ? Forcing the format like I did seems to patch the issue, but I'd still want to know what exactly is going on.

Aucun commentaire:

Enregistrer un commentaire