Rails - escaping backslashes in params causing hav

2019-06-05 08:42发布

问题:

I have a form that passes the same parameters as the form before it:

<%= form_tag({:controller => "workouts", :action => "random"}) do %>
<%= hidden_field_tag :workout, params[:workout] %>
<%= hidden_field_tag :time, params[:time] %>
<%= submit_tag "Get Another", :class => 'btn' %>

The first form works fine, the second form to "get another" gives me the error can't convert Symbol into Integer for this line:

@equipment_ids = params[:workout][:equipment_ids].collect{|s| s.to_i}

The params of the first and second form being passed are:

 {"utf8"=>"✓",
 "authenticity_token"=>"qj/Q/YWvLKK3A3paAnEom4oTFtq44daX6dvEb8qmgtE=",
 "workout"=>{"equipment_ids"=>["",
 "508",
 "518"]},
 "time"=>"25",
 "commit"=>"Get Workout"}


 {"utf8"=>"✓",
  "authenticity_token"=>"qj/Q/YWvLKK3A3paAnEom4oTFtq44daX6dvEb8qmgtE=",
  "workout"=>"{\"equipment_ids\"=>[\"\",
  \"508\",
  \"518\"]}",
  "time"=>"25",
  "commit"=>"Get Another"}

The only difference is the escaping backslashes. I'm not sure why these would cause a problem?

回答1:

Changed the hidden field tag to:

<%= hidden_field_tag "workout[equipment_ids][]", params[:workout][:equipment_ids] %>


回答2:

I just went into the same problem when trying to manually submit a form with a custom POST request. The problem seems to be that net/http post_form method can only handle a single hash where all the values are Strings. If you have hash inside hash (like in the form that scaffold generates), it treats the inner hash as a String, and adds the nasty backslashes that, as you just saw cause havoc :)

The solution for me was to use the lower level "post" method, and to manually encode the hash. Define this module:

module HashToHttpParams
   def to_http_params
     map do |k, v|
       if v.is_a?(Hash)
         v.map do |kk, vv|
           "#{k}[#{kk}]=#{vv}"
         end.join('&')
       else
         "#{k}=#{v}"
       end
     end.join('&')
   end
 end

And then add it to the Hash class in your code:

Hash.send(:include, HashToHttpParams)

Finally encode your params hash before using it. In my code this looks like:

Net::HTTP.start("localhost",3000) do |http|  
  http.post("/tests", params.to_http_params)  
end 

Don't know if there's a better solution, but this worked for me.

Source: http://porras.lacoctelera.net/post/2007/10/08/enviando-formularios-con-parametros-compuestos-con-ruby-y-net#c4300080



回答3:

As Hallucynogenyc pointed out, this is caused by the .post_form (docs) method only wanting a non-nested hash that is strings. I had this same problem, and solved it by switching to use the .post method.

require "net/http"
uri = URI('http://www.yoururl.com')
http = Net::HTTP.new(uri.host)
response = http.post(uri.path, params.to_query) 

The .to_query method is also useful for converting hashes.

Another way to solve it is to not use the rails form method to create your params. If you just use straight html, for some reason the .post_form method likes it better.

Email <input name="student_email" type="email" autofocus="true">