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 try开发者_开发技巧ing 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
精彩评论