during my rails development i recently came across the problem mentioned here. this is my concrete scenario…
first of all there are two model elements referenced by belongs_to
resp. has_many
:
class WorkingTime < ActiveRecord::Base
belongs_to :project
validates_presence_of :project, :message => 'Please select a project!'
validates_associated :project
validates_presence_of :hours_worked
end
class Project < ActiveRecord::Base
has_many :working_times
end
the input form to create an instance of this model looks something like this:
[...]
<%= error_messages_for 'working_time' %>
<label for="project_of_working_time">Project</label>
<%= select :working_time, :project_id,
Project.find(:all).collect {|p| [ p.name, p.id ] },
{ :include_blank => true }, :class => "working_time_select" %>
<label for="working_time_hours_and_minutes_worked">Hours Worked</label>
<%= text_field 'working_time', 'hours_worked', :size => 5 %>
[...]
now if you try to save the form without selecting a project an appropriate error message is shown. this is not really remarkable. but the problem is that the select input field isn’t highlighted correctly like other input fields (i.e. the hours_worked if it is empty). i had a hard time to figure out the reason for this.
the error highlighting is based on the errors
object that is passed to the view in case of validation errors. when the view is evaluated every input field looks in this object for an error associated to it by its name. if the method errors.on(name of input field)
returns a value, a html-snipped is wrapped around the input field (btw, if you want to change the snipped, look here). here is an example for the input textfield hours_worked
:
<div class="fieldWithErrors">
<input id="workind_time_hours_worked"
name="working_time[hours_worked]" size="5" type="text" value="" />
</div>
the issue with the above mentioned working_time
/ project
relation is that the validation error is mapped to the field project
and not to project_id
, since this is what i described in the model working_time
. because the view cannot get the link to the project
-error, the field will not be highlighted. you can validate this with a unit-test:
require 'working_time'
class WorkingTimeTest < Test::Unit::TestCase
def test_create_without_project
@working_time = WorkingTime.new
@working_time.hours_worked = 3
result = @working_time.save
assert !result
errors = @working_time.errors
assert_not_nil errors[:project]
assert includes_match?(errors[:project], 'Please select a project!')
end
end
the only solution is to change the validation in the working_time
model from project
to project_id
. this is quite confusing because the working_time
model actually doesn’t have a project_id field. what makes this even worse is that you also get validation errors if a project
instance will be set in the working_time
model. therefore the following test always fails:
require 'working_time'
require 'project'
class WorkingTimeTest < Test::Unit::TestCase
def test_create_with_project
@working_time = WorkingTime.new
@working_time.hours_worked = 3
@working_time.project = Project.find(1)
result = @working_time.save
assert result
end
end
i hope this issue will be fixed in a future version of rails.
4 thoughts on “rails error wrapping for select input fields of referenced models”
Comments are closed.