POSTing JSON body causes Rack::QueryParser::InvalidParameterError - ruby-on-rails

I'm simply trying to POST a JSON content-type http request from one Rails server to another. Putting a % character in a value string in the JSON is causing the Rack::QueryParser::InvalidParameterError on the receiving server.
On Server A, I use the httparty gem to perform a POST request w/ a JSON body
obj = {"key":"<%= #results %>"}
resp = HTTParty.post('https://test-url.com/data',
:body => obj.to_json,
:options => { :headers => { 'Content-Type' => 'application/json', 'Accept' => 'application/json' } })
On Server B, I just parse the JSON from the request body
req_body = request.body.read()
req_body_json = JSON.parse req_body
# do work with json
This process works fine unless the obj = {"key":"<%= #results %>"} contains % chars, in which case this occurs on server B:
Started POST "/data" for 10.244.1.3 at 2018-01-02 19:27:04 +0000
F, [2018-01-02T19:27:04.245275 #1] FATAL -- :
F, [2018-01-02T19:27:04.245331 #1] FATAL -- : Rack::QueryParser::InvalidParameterError (invalid %-encoding ({"key":"\u003c%)):
F, [2018-01-02T19:27:04.245358 #1] FATAL -- :
F, [2018-01-02T19:27:04.245397 #1] FATAL -- : rack (2.0.3) lib/rack/query_parser.rb:72:in `rescue in parse_nested_query'
rack (2.0.3) lib/rack/query_parser.rb:60:in `parse_nested_query'
rack (2.0.3) lib/rack/request.rb:468:in `parse_query'
rack (2.0.3) lib/rack/request.rb:343:in `POST'
actionpack (5.1.4) lib/action_dispatch/http/request.rb:362:in `block (2 levels) in POST'
actionpack (5.1.4) lib/action_dispatch/http/parameters.rb:107:in `block in parse_formatted_parameters'
actionpack (5.1.4) lib/action_dispatch/http/parameters.rb:107:in `fetch'
actionpack (5.1.4) lib/action_dispatch/http/parameters.rb:107:in `parse_formatted_parameters'
actionpack (5.1.4) lib/action_dispatch/http/request.rb:361:in `block in POST'
rack (2.0.3) lib/rack/request.rb:57:in `fetch'
rack (2.0.3) lib/rack/request.rb:57:in `fetch_header'
actionpack (5.1.4) lib/action_dispatch/http/request.rb:360:in `POST'
...
When I change obj = {"key":"<%= #results %>"} to obj = {"key":"<= #results>"} the exception does not occur.
As far I know % is a valid in JSON, what am I missing here?

Considering they way how it's implemented here: https://github.com/jnunemaker/httparty/blob/38125db0d079d52a3b0da815150fa2135bb0110d/lib/httparty.rb#L559,
Your body and headers hash keys should be siblings, try the next:
resp = HTTParty.post('https://test-url.com/data',
:body => obj.to_json,
:headers => { 'Content-Type' => 'application/json',
'Accept' => 'application/json' }
)

Related

ActionController::UnknownFormat when uploading image with Dropzone

I have a new error regarding my Dropzone JS snippet. I use dropzone to upload images from an #Edit view.
One the images are created by another controller create action, I redirect to that very edit action.
This is where I get this new error :
Completed 406 Not Acceptable in 14ms (ActiveRecord: 1.1ms)
ActionController::UnknownFormat (PhotographesController#edit is missing a template for this request format and variant.
request.formats: ["application/json"]
request.variant: []):
actionpack (5.2.0) lib/action_controller/metal/implicit_render.rb:42:in `default_render'
actionpack (5.2.0) lib/action_controller/metal/basic_implicit_render.rb:6:in `block in send_action'
actionpack (5.2.0) lib/action_controller/metal/basic_implicit_render.rb:6:in `tap'
actionpack (5.2.0) lib/action_controller/metal/basic_implicit_render.rb:6:in `send_action'
actionpack (5.2.0) lib/abstract_controller/base.rb:194:in `process_action'
.....
It used to work perfectly in the past. But since I have set this snippet in place I have done quite a few things: installing gem "serviceworker-rails" and deferring the javascript..
I have undeferred the Javascript but the error is still here. Is it related to the serviceworker gem ?
EDIT
Dropzone snippet inside Photographes#edit view (inline)
<script>
// Dropzone = dynamic
var AUTH_TOKEN=$('meta[name="csrf-token"]').attr('content');
Dropzone.autoDiscover = false;
var myDropzone = new Dropzone("div#mydropzone",{
url: "<%= photographe_photographephotos_path(#photographe.hashed_id) %>",
autoProcessQueue: false,
autoDiscover: false,
uploadMultiple: true,
addRemoveLinks: true,
// clickable: false,
parallelUploads: 12,
maxFilesize: 5,
maxFiles: 12,
acceptedFiles: 'image/jpg, image/jpeg, image/png',
params:{
'authenticity_token': AUTH_TOKEN
},
successmultiple: function(data,response){
$('#msgBoard').append(response.message).addClass("alert alert-success");
$('#msgBoard').delay(2000).fadeOut();
$('#fileslist').val(response.filesList);
$('#photographedit').off('submit').submit();
}
});
$('#photographedit').submit(function(e){
if(myDropzone.getQueuedFiles().length > 0){
e.preventDefault();
myDropzone.processQueue();
}
});
</script>
Then Photographephotos#create
def create
#photographe = Photographe.find_by(hashed_id: params[:photographe_hashed_id])
if params[:file].present?
uploaded_pics = params[:file]
maximum_images=12
available_images = maximum_images - #photographe.photographephotos.count
n_keys = uploaded_pics.keys.first(available_images)
filtered_pics = uploaded_pics.slice(*n_keys)
filtered_pics.each do |index,pic|
#image = #photographe.photographephotos.new
#image.image = pic
#image.image_file_name = "Copyright" + #photographe.professionnel.first_name.to_s + #photographe.professionnel.last_name.to_s + ".JPG"
#image.save
end
end
redirect_to edit_photographe_path(#photographe.hashed_id)
end
The redirect at the end returns (should return) to the Photographes#edit view. What is funny if it used to work properly ...
I see that people used to have same problem with Jbuilder as per github. I have updated Jbuilder gem with no success.
Also the pictures are properly updated by paperclip. I get this error from logs when the redirection fails at the end of the images creation.
It seems like the controller is trying to render a template in a format that doesn't exist, maybe you can try specifying the format explicitly like this:
redirect_to edit_photographe_path(#photographe.hashed_id), :format => :html
This may happen if you received a request in a specific format and want to render a template in a different one.
I'm not sure if, in your case, the :format option should go inside the _path() or the redirect_to() method. If the above doesn't work try this:
redirect_to edit_photographe_path(#photographe.hashed_id, :format => :html)

Rails wrong number of arguments (1 for 2) in controller

I'm trying to make a simple calculator that converts farenheit to celsius, using Ruby on Rails. I keep getting the error "Wrong number of arguments (1 for 2)" after I enter some input value. This app has been alot more difficult than it should be. I've been fixing errors as they come up, but can't figure this one out. Other posts I've read are much different and more elaborate than this simple app I'm trying to make. Thanks for any help.
The controller ...
class CalculatorController < ApplicationController
def calculate
#farenheit = params[:temperature]
unless #farenheit.blank?
#farenheit = Temperature.calculate({ :farenheit => #farenheit})
end
#celsius = (#farenheit - 32) * (5.0 / 9.0)
end
private
## Strong Parameters
def user_params
params.require(:farenheit)
end
end
The model...
class Temperature < ActiveRecord::Base
# attr_accessible :farenheit
validates_presence_of :farenheit
validates_numericality_of :farenheit
end
The view...
<h1>Temperature Calculator</h1>
<%= form_tag(calculator_calculate_path, method: "get", action: "calculate") do |form|%>
<p>Please enter a temperature in degrees Farenheit</p>
<%= text_field_tag 'temperature', #farenheit %></p>
<%= submit_tag 'Convert' %>
<h2>Result: </h2>
<h3> <% #celsius %> </h3>
<% end %>
The stack trace (first 10 lines)...
activerecord (4.1.6) lib/active_record/relation/calculations.rb:109:in `calculate'
C:in `calculate'
app/controllers/calculator_controller.rb:6:in `calculate'
actionpack (4.1.6) lib/action_controller/metal/implicit_render.rb:4:in `send_action'
actionpack (4.1.6) lib/abstract_controller/base.rb:189:in `process_action'
actionpack (4.1.6) lib/action_controller/metal/rendering.rb:10:in `process_action'
actionpack (4.1.6) lib/abstract_controller/callbacks.rb:20:in `block in process_action'
activesupport (4.1.6) lib/active_support/callbacks.rb:113:in `call'
activesupport (4.1.6) lib/active_support/callbacks.rb:113:in `call'
You've defined an instance method calculate in your CalculatorController, but calculate is also a class method defined in ActiveRecord. It is the ActiveRecord class method that you are calling when you say
#farenheit = Temperature.calculate({ :farenheit => #farenheit})
and that method requires at least two arguments. Here are the docs:
calculate(operation, column_name, options = {}) public
This calculates aggregate values in the given column. Methods for
count, sum, average, minimum, and maximum have been added as
shortcuts. Options such as :conditions, :order, :group, :having, and
:joins can be passed to customize the query.
See http://apidock.com/rails/ActiveRecord/Calculations/ClassMethods/calculate
I'm not sure why you're using the calculate class method though. Why not use only your calculation of #celcius? The following should get your calculate method working without an ArgumentError:
def calculate
#farenheit = params[:temperature]
unless #farenheit.blank?
#celsius = (#farenheit.to_i - 32) * (5.0 / 9.0)
end
end

high_voltage gem not working for URLs not beginning with /pages

I can't seem to get thoughtbot's High Voltage gem to work for URLs that don't start with /pages. For URLs like www.example.com/pages/company/about, it works perfect. When I add this route:
match '/company/about' => 'high_voltage/pages#show', :id => 'about'
I get an internal server error:
Started GET "/company/about" for 127.0.0.1 at 2012-10-09 18:03:45 -0700
Processing by HighVoltage::PagesController#show as HTML
Parameters: {"id"=>"about"}
Completed 500 Internal Server Error in 2ms
ActionController::RoutingError (No such page: about):
high_voltage (1.2.0) app/controllers/high_voltage/pages_controller.rb:9:in `block in <class:PagesController>'
activesupport (3.2.8) lib/active_support/rescuable.rb:80:in `call'
activesupport (3.2.8) lib/active_support/rescuable.rb:80:in `rescue_with_handler'
actionpack (3.2.8) lib/action_controller/metal/rescue.rb:15:in `rescue_with_handler'
However, if I just put the about.html.erb page inside app/views/pages/about.html.erb, then everything works as expected with this route:
match '/:id' => 'high_voltage/pages#show'
or this route works too:
match '/about' => 'high_voltage/pages#show', :id => 'about'
jferris at GitHub informed me I have to make the id 'company/about' above. And that worked.

stack level to deep Rails 2.3.14

I'm developing a plugin for a management framework and when I start the webrick server in the development mode, a strange error raises(stack level too deep). It happens when an action (e.g. the show action) starts to render a template. Unfortunately i have no idea why this is happen.
SystemStackError in Stories#show
Showing vendor/plugins/stories/app/views/stories/show.rhtml where line #5 raised:
stack level too deep
Extracted source (around line #5):
5: link_to_if_authorized 'aa', {:controller => "stories", :action => "index", :id => #story.id, :project_id => #story.project.id}, :title => l(:view_story), :class => 'icon icon-zoom-out'
6: link_to_if_authorized 'bb', {:controller => "stories", :action => "edit", :id => #story.id, :project_id => #story.project.id}, :title => l(:button_edit), :class => 'icon icon-edit'
7: link_to 'bb', {:id => #story.id, :project_id => #story.project.id}, :confirm => 'Really delete?', :method => :delete, :class => 'icon icon-del' if User.current.allowed_to? (:delete_stories, #project)
RAILS_ROOT: /home/haendwic/Documents/Aptana Studio 3 Workspace/1.4-stable-SVN
Application Trace | Framework Trace | Full Trace
/var/lib/gems/1.8/gems/activerecord-2.3.14/lib/active_record/attribute_methods.rb:248:in method_missing'
/var/lib/gems/1.8/gems/activerecord-2.3.14/lib/active_record/attribute_methods.rb:249:in method_missing'
/var/lib/gems/1.8/gems/activerecord-2.3.14/lib/active_record/associations /association_proxy.rb:215:in send'
/var/lib/gems/1.8/gems/activerecord-2.3.14/lib/active_record/associations/association_proxy.rb:215:in method_missing'
/home/haendwic/Documents/Aptana Studio 3 Workspace/1.4-stable-SVN/vendor/plugins/stories/app/views/stories/show.rhtml:5:in _run_rhtml_vendor47plugins47stories47app47views47stories47show46rhtml'
/var/lib/gems/1.8/gems/actionpack-2.3.14/lib/action_view/renderable.rb:34:in send'
/var/lib/gems/1.8/gems/actionpack-2.3.14/lib/action_view/renderable.rb:34:in render'
/var/lib/gems/1.8/gems/actionpack-2.3.14/lib/action_view/base.rb:306:in with_template'
/var/lib/gems/1.8/gems/actionpack-2.3.14/lib/action_view/renderable.rb:30:in render'
/var/lib/gems/1.8/gems/actionpack-2.3.14/lib/action_view/template.rb:205:in render_template'
/var/lib/gems/1.8/gems/actionpack-2.3.14/lib/action_view/base.rb:265:in render'
/var/lib/gems/1.8/gems/actionpack-2.3.14/lib/action_view/base.rb:348:in _render_with_layout'
/var/lib/gems/1.8/gems/actionpack-2.3.14/lib/action_view/base.rb:262:in render'
/var/lib/gems/1.8/gems/actionpack-2.3.14/lib/action_controller/base.rb:1252:in render_for_file'
/var/lib/gems/1.8/gems/actionpack-2.3.14/lib/action_controller/base.rb:936:in render_without_benchmark'
/var/lib/gems/1.8/gems/actionpack-2.3.14/lib/action_controller/benchmarking.rb:51:in render'
/var/lib/gems/1.8/gems/activesupport-2.3.14/lib/active_support/core_ext/benchmark.rb:17:in ms'
/usr/lib/ruby/1.8/benchmark.rb:308:in realtime'
/var/lib/gems/1.8/gems/activesupport-2.3.14/lib/active_support/core_ext/benchmark.rb:17:in ms'
/var/lib/gems/1.8/gems/actionpack-2.3.14/lib/action_controller/benchmarking.rb:51:in render'
/home/haendwic/Documents/Aptana Studio 3 Workspace/1.4-stable-SVN/vendor/plugins/stories/app/controllers/stories_controller.rb:104:in show'
/var/lib/gems/1.8/gems/actionpack-2.3.14/lib/action_controller/mime_responds.rb:135:in call'
/var/lib/gems/1.8/gems/actionpack-2.3.14/lib/action_controller/mime_responds.rb:135:in custom'
/var/lib/gems/1.8/gems/actionpack-2.3.14/lib/action_controller/mime_responds.rb:179:in call'
/var/lib/gems/1.8/gems/actionpack-2.3.14/lib/action_controller/mime_responds.rb:179:in respond'
/var/lib/gems/1.8/gems/actionpack-2.3.14/lib/action_controller/mime_responds.rb:173:in each'
/var/lib/gems/1.8/gems/actionpack-2.3.14/lib/action_controller/mime_responds.rb:173:in respond'
/var/lib/gems/1.8/gems/actionpack-2.3.14/lib/action_controller/mime_responds.rb:107:in respond_to'
/home/haendwic/Documents/Aptana Studio 3 Workspace/1.4-stable-SVN/vendor/plugins/stories/app/controllers/stories_controller.rb:102:in show'
/var/lib/gems/1.8/gems/actionpack-2.3.14/lib/action_controller/base.rb:1333:in send'
/var/lib/gems/1.8/gems/actionpack-2.3.14/lib/action_controller/base.rb:1333:in perform_action_without_filters'
/var/lib/gems/1.8/gems/actionpack-2.3.14/lib/action_controller/filters.rb:617:in call_filters'
/var/lib/gems/1.8/gems/actionpack-2.3.14/lib/action_controller/filters.rb:610:in perform_action_without_benchmark'
/var/lib/gems/1.8/gems/actionpack-2.3.14/lib/action_controller/benchmarking.rb:68:in perform_action_without_rescue'
/var/lib/gems/1.8/gems/activesupport-2.3.14/lib/active_support/core_ext/benchmark.rb:17:in ms'
/usr/lib/ruby/1.8/benchmark.rb:308:in realtime'
/var/lib/gems/1.8/gems/activesupport-2.3.14/lib/active_support/core_ext/benchmark.rb:17:in ms'
/var/lib/gems/1.8/gems/actionpack-2.3.14/lib/action_controller/benchmarking.rb:68:in perform_action_without_rescue'
/var/lib/gems/1.8/gems/actionpack-2.3.14/lib/action_controller/rescue.rb:160:in perform_action_without_flash'
/var/lib/gems/1.8/gems/actionpack-2.3.14/lib/action_controller/flash.rb:151:in perform_action'
/var/lib/gems/1.8/gems/actionpack-2.3.14/lib/action_controller/base.rb:532:in send'
/var/lib/gems/1.8/gems/actionpack-2.3.14/lib/action_controller/base.rb:532:in process_without_filters'
/var/lib/gems/1.8/gems/actionpack-2.3.14/lib/action_controller/filters.rb:606:in process'
/var/lib/gems/1.8/gems/actionpack-2.3.14/lib/action_controller/base.rb:391:in process'
/var/lib/gems/1.8/gems/actionpack-2.3.14/lib/action_controller/base.rb:386:in call'
/var/lib/gems/1.8/gems/actionpack-2.3.14/lib/action_controller/routing/route_set.rb:438:in call'
/var/lib/gems/1.8/gems/actionpack-2.3.14/lib/action_controller/dispatcher.rb:87:in dispatch'
/var/lib/gems/1.8/gems/actionpack-2.3.14/lib/action_controller/dispatcher.rb:121:in _call'
/var/lib/gems/1.8/gems/actionpack-2.3.14/lib/action_controller/dispatcher.rb:130:in build_middleware_stack'
/var/lib/gems/1.8/gems/activerecord-2.3.14/lib/active_record/query_cache.rb:29:in call'
/var/lib/gems/1.8/gems/activerecord-2.3.14/lib/active_record/query_cache.rb:29:in call'
/var/lib/gems/1.8/gems/activerecord-2.3.14/lib/active_record/connection_adapters/abstract/query_cache.rb:34:in cache'
/var/lib/gems/1.8/gems/activerecord-2.3.14/lib/active_record/query_cache.rb:9:in cache'
/var/lib/gems/1.8/gems/activerecord-2.3.14/lib/active_record/query_cache.rb:28:in call'
/var/lib/gems/1.8/gems/activerecord-2.3.14/lib/active_record/connection_adapters/abstract/connection_pool.rb:361:in call'
/var/lib/gems/1.8/gems/actionpack-2.3.14/lib/action_controller/string_coercion.rb:25:in call'
/var/lib/gems/1.8/gems/rack-1.1.3/lib/rack/head.rb:9:in call'
/var/lib/gems/1.8/gems/rack-1.1.3/lib/rack/methodoverride.rb:24:in call'
/var/lib/gems/1.8/gems/actionpack-2.3.14/lib/action_controller/params_parser.rb:15:in call'
/var/lib/gems/1.8/gems/actionpack-2.3.14/lib/action_controller/session /cookie_store.rb:99:in call'
/var/lib/gems/1.8/gems/actionpack-2.3.14/lib/action_controller/failsafe.rb:26:in call'
/var/lib/gems/1.8/gems/rack-1.1.3/lib/rack/lock.rb:11:in call'
/var/lib/gems/1.8/gems/rack-1.1.3/lib/rack/lock.rb:11:in synchronize'
/var/lib/gems/1.8/gems/rack-1.1.3/lib/rack/lock.rb:11:in call'
/var/lib/gems/1.8/gems/actionpack-2.3.14/lib/action_controller/dispatcher.rb:114:in call'
/var/lib/gems/1.8/gems/actionpack-2.3.14/lib/action_controller/reloader.rb:34:in run'
/var/lib/gems/1.8/gems/actionpack-2.3.14/lib/action_controller/dispatcher.rb:108:in call'
/var/lib/gems/1.8/gems/rails-2.3.14/lib/rails/rack/static.rb:31:in call'
/var/lib/gems/1.8/gems/rack-1.1.3/lib/rack/urlmap.rb:47:in call'
/var/lib/gems/1.8/gems/rack-1.1.3/lib/rack/urlmap.rb:41:in each'
/var/lib/gems/1.8/gems/rack-1.1.3/lib/rack/urlmap.rb:41:in call'
/var/lib/gems/1.8/gems/rails-2.3.14/lib/rails/rack/log_tailer.rb:17:in call'
/var/lib/gems/1.8/gems/rack-1.1.3/lib/rack/content_length.rb:13:in call'
/var/lib/gems/1.8/gems/rack-1.1.3/lib/rack/handler/webrick.rb:48:in service'
/usr/lib/ruby/1.8/webrick/httpserver.rb:104:in service'
/usr/lib/ruby/1.8/webrick/httpserver.rb:65:in run'
/usr/lib/ruby/1.8/webrick/server.rb:173:in start_thread'
/usr/lib/ruby/1.8/webrick/server.rb:162:in start'
/usr/lib/ruby/1.8/webrick/server.rb:162:in start_thread'
/usr/lib/ruby/1.8/webrick/server.rb:95:in start'
/usr/lib/ruby/1.8/webrick/server.rb:92:in each'
/usr/lib/ruby/1.8/webrick/server.rb:92:in start'
/usr/lib/ruby/1.8/webrick/server.rb:23:in start'
/usr/lib/ruby/1.8/webrick/server.rb:82:in start'
/var/lib/gems/1.8/gems/rack-1.1.3/lib/rack/handler/webrick.rb:14:in run'
/var/lib/gems/1.8/gems/rails-2.3.14/lib/commands/server.rb:111
script/server:3:in require'
script/server:3
Request
Parameters:
{"project_id"=>"1",
"id"=>"2"}
Show session dump
Response
Headers:
{"Cache-Control"=>"no-cache",
"Content-Type"=>"text/html"}
and here is the action from the controller
def show
#edit_allowed = User.current.allowed_to?(:edit_stories, #project)
respond_to do |format|
format.html {
render :template => 'stories/show'
}
format.api
format.pdf { send_data(story_to_pdf(#story), :type => 'application/pdf', :filename => "#{#project.identifier}-#{#story.id}.pdf") }
end
end
and at last a part of the view
link_to_if_authorized 'aa', {:controller => "stories", :action => "index", :id => #story.id, :project_id => #story.project.id}, :title => l(:view_story), :class => 'icon icon-zoom-out'
link_to_if_authorized 'bb', {:controller => "stories", :action => "edit", :id => #story.id, :project_id => #story.project.id}, :title => l(:button_edit), :class => 'icon icon-edit'
link_to 'bb', {:id => #story.id, :project_id => #story.project.id}, :confirm => 'Really delete?', :method => :delete, :class => 'icon icon-del' if User.current.allowed_to?(:delete_stories, #project)
Maybe it's important to say, that in the production mode the plugin is stable and routes the actions (incl. show) correctly
This is typically caused by you (or others) patching core models (probably the Project model) from a plugin without taking the rails reloader into account.
If you override methods (e.g. using alias_method_chain) and your patch is loaded twice, you can easily create an infinite loop when calling the old method.
# This is our initial class
class MyClass
def foo
puts "original foo"
end
end
module Patch
def self.included(base)
base.alias_method_chain :foo, :feature
end
def foo_with_feature
foo_without_feature # call the "original" method
puts "foo with feature"
end
end
# patch the class
MyClass.send(:include, Patch)
# Now call the patched method
MyClass.new.foo
# prints:
# original foo
# foo with feature
foo now refers to the method foo_with_feature while the original foo method now is accessible from foo_without_feature
All right, until now everything looked good. Now let's see what happens, if we load our patch again
# patch again
MyClass.send(:include, Patch)
# And call the method again
MyClass.new.foo
# SystemStackError: stack level too deep
# from (irb):7:in `foo_without_feature'
# from (irb):7:in `foo'
# from (irb):27
You see a SystemStackError caused by an infinite loop. This is because after the second loading of the patch, foo_without_feature now refers to the foo_with_feature method from the first patch. When calling it, it will over and over again call foo_without_feature until the stack is full.
You said that it only crashes on the second request. This is exactly the typical behavior when something is odd on the class reloader. By default, Rails will reload all classes on every request in development mode but only once in production mode.
Taming the rails reloader is a bit tricky sometimes. As some general guidelines, you should
use require_dependency instead of require when loading patches
load your patches using Dispatcher.to_prepare
always declare the patched classes unloadable
The most critical part is using Dispatcher.to_prepare. It is a callback which is called once in production mode and before each request in development mode and is thus the ideal place for loading patches.
As a side note though: When using Redmine 2 (or the upcoming ChiliProject 4), i.e. Rails 3, the class patching will be rather different from this approach - most probably easier.
The "stack level too deep" error means that you have a stack overflow (it happens often enough to have a site named after it). That occurs when a function calls itself indefinitely or when two functions call each other indefinitely.
Your error happens on line 5, so I'd check the source for link_to_if_authorized. Something in there is causing an infinite loop.

Rails error with validation and multiple models, can't convert HashWithIndifferentAccess into String

I haven't used rails since version 1.2 or so and a few things have changed. I have an issue where I am trying to save an empty model to get validation errors on attributes using :validates_presence_of and instead I am getting the error 'can't convert HashWithIndifferentAccess into String'. I will attempt to simplify my code to get the point across as tersely as possible...
my model:
class Project < ActiveRecord::Base
validates_presence_of :title, :description
validates_uniqueness_of :title
has_one :address
accepts_nested_attributes_for :address, :allow_destroy => true
end
Child model:
class Address < ActiveRecord::Base
validates_presence_of :title, :street
belongs_to :project
end
controller:
class ProjectsController < ApplicationController
def create
#project = Project.new(params[:project])
if #project.save
flash[:notice] = #project.title + ' successfully created'
redirect_to projects_path
else
render :action => 'new'
end
end
end
view:
<%= error_messages_for 'project' %>
<% form_for #project do |f| %>
<table width="100%" cellpadding="3" cellspacing="0">
<tr>
<td class="adminlabel">
<label for="Title">Title</label>
</td>
<td class="adminbody">
<%= f.text_field :title %>
</td>
</tr>
.....
<% f.fields_for :address do |address| %>
....
This code adds and updates just fine as long as I fill in all the required fields, if I leave any blank I get the error mentioned above, not the most graceful way of alerting users there is an issue ;)
Request params:
{"commit"=>"Save",
"project"=>{"title"=>"",
"notes"=>"",
"description"=>"",
"address_attributes"=>{"city"=>"",
"zip"=>"",
"title"=>"",
"country"=>"",
"suite"=>"",
"street"=>"",
"state"=>""}},
"authenticity_token"=>"iNPQZrf/oBv22vaI0toTGhknwx0aAU3BSvnIh6qgYQ8="}
I have been searching for days and am at my wits end, if anyone can shed a little light on this for me I would greatly appreciate it.
Thanks in advance!
Brendan
PS - the stack trace as requested:
.../app/controllers/projects_controller.rb:27:in `+'
.../app/controllers/projects_controller.rb:27:in `create'
../actionpack-2.3.4/lib/action_controller/base.rb:1331:in `send'
../actionpack-2.3.4/lib/action_controller/base.rb:1331:in `perform_action_without_filters'
../actionpack-2.3.4/lib/action_controller/filters.rb:617:in `call_filters'
../actionpack-2.3.4/lib/action_controller/filters.rb:610:in `perform_action_without_benchmark'
../actionpack-2.3.4/lib/action_controller/benchmarking.rb:68:in `perform_action_without_rescue'
../activesupport-2.3.4/lib/active_support/core_ext/benchmark.rb:17:in `ms'
../activesupport-2.3.4/lib/active_support/core_ext/benchmark.rb:10:in `realtime'
../activesupport-2.3.4/lib/active_support/core_ext/benchmark.rb:17:in `ms'
../actionpack-2.3.4/lib/action_controller/benchmarking.rb:68:in `perform_action_without_rescue'
../actionpack-2.3.4/lib/action_controller/rescue.rb:160:in `perform_action_without_flash'
../actionpack-2.3.4/lib/action_controller/flash.rb:146:in `perform_action'
../actionpack-2.3.4/lib/action_controller/base.rb:532:in `send'
../actionpack-2.3.4/lib/action_controller/base.rb:532:in `process_without_filters'
../actionpack-2.3.4/lib/action_controller/filters.rb:606:in `process'
../actionpack-2.3.4/lib/action_controller/base.rb:391:in `process'
../actionpack-2.3.4/lib/action_controller/base.rb:386:in `call'
../actionpack-2.3.4/lib/action_controller/routing/route_set.rb:437:in `call'
../actionpack-2.3.4/lib/action_controller/dispatcher.rb:87:in `dispatch'
../actionpack-2.3.4/lib/action_controller/dispatcher.rb:121:in `_call'
../actionpack-2.3.4/lib/action_controller/dispatcher.rb:130:in `build_middleware_stack'
../activerecord-2.3.4/lib/active_record/query_cache.rb:29:in `call'
../activerecord-2.3.4/lib/active_record/query_cache.rb:29:in `call'
../activerecord-2.3.4/lib/active_record/connection_adapters/abstract/query_cache.rb:34:in `cache'
..activerecord-2.3.4/lib/active_record/query_cache.rb:9:in `cache'
../activerecord-2.3.4/lib/active_record/query_cache.rb:28:in `call'
../activerecord-2.3.4/lib/active_record/connection_adapters/abstract/connection_pool.rb:361:in `call'
../rack-1.0.1/lib/rack/head.rb:9:in `call'
../rack-1.0.1/lib/rack/methodoverride.rb:24:in `call'
../actionpack-2.3.4/lib/action_controller/params_parser.rb:15:in `call'
../actionpack-2.3.4/lib/action_controller/session/cookie_store.rb:93:in `call'
../actionpack-2.3.4/lib/action_controller/failsafe.rb:26:in `call'
../rack-1.0.1/lib/rack/lock.rb:11:in `call'
../rack-1.0.1/lib/rack/lock.rb:11:in `synchronize'
../rack-1.0.1/lib/rack/lock.rb:11:in `call'
../actionpack-2.3.4/lib/action_controller/dispatcher.rb:114:in `call'
../actionpack-2.3.4/lib/action_controller/reloader.rb:34:in `run'
../actionpack-2.3.4/lib/action_controller/dispatcher.rb:108:in `call'
../rails-2.3.4/lib/rails/rack/static.rb:31:in `call'
../rack-1.0.1/lib/rack/urlmap.rb:46:in `call'
../rack-1.0.1/lib/rack/urlmap.rb:40:in `each'
../rack-1.0.1/lib/rack/urlmap.rb:40:in `call'
../rails-2.3.4/lib/rails/rack/log_tailer.rb:17:in `call'
../rack-1.0.1/lib/rack/content_length.rb:13:in `call'
../rack-1.0.1/lib/rack/chunked.rb:15:in `call'
../rack-1.0.1/lib/rack/handler/mongrel.rb:64:in `process'
..... etc.
A bit lengthy, sorry ;)
Try adding
#project.address.build
to your controller. You need to instantiate the address object.
The trace doesn't lie. You're having issues with a line 27. The code you posted doesn't have 37 lines, but based on the trace I'm willing to bet it's this line. Because none others have have a '+'. If there was an implicit + its caller would've been listed in the trace.
flash[:notice] = #project.title + ' successfully created'
It's odd that it's reaching that point based on your validations. validates_presence_of should add errors on attributes that are either nil, false or "". Does the validation fail as expected when run in the console?
Here's a console friendly version of your code that could be used to track down your issue. You should be able to just paste it into the console to help track down your issue.
params = {
"project"=> {
"title"=>"", "notes"=>"","description"=>"",
"address_attributes"=>{
"city"=>"", "zip"=>"","title"=>"","country"=>"",
"suite"=>"","street"=>"","state"=>""
}
}
flash = {}
#project = Project.new(params[:project])
if #project.save
flash[:notice] = #project.title + ' successfully created'
puts "Saved. Flash: #{flash[:notice]}"
else
puts "validations failed:"
puts #project.errors.full_messages.map{|m| "\t#{m}"}.join("\n")
end

Resources