我遇到了一个很奇怪的问题。我有 Timetable
模型并尝试编写我的自定义验证。所以,现在我只是想为字段添加测试错误以确保一切正常。但它不起作用。所以,我尝试更新时间表模型的对象,但是当我不使用我的测试自定义验证时,一切正常。否则我会收到这样的错误:
NoMethodError in Timetables#update
undefined method `map' for nil:NilClass
32:
33: <div class="controls">
34: <%= f.select( :curriculum_id,
35: options_for_select( @subjects_with_curriculums,
36: @tt.curriculum_id ),
37: { :include_blank => true }) %>
38: </div>
这是我的模型:
# == Schema Information
#
# Table name: timetables
#
# id :integer not null, primary key
# curriculum_id :integer
# school_class_id :integer
# tt_day_of_week :string(255)
# tt_number_of_lesson :integer
# tt_room :string(255)
# tt_type :string(255)
# created_at :datetime not null
# updated_at :datetime not null
#
class Timetable < ActiveRecord::Base
belongs_to :curriculum
belongs_to :school_class
has_many :lessons
validates :school_class_id, :presence => { :message => "should exist" }
validates :tt_day_of_week,
:presence => true,
:inclusion => { :in => %w(Mon Tue Wed Thu Fri) }
validates :tt_number_of_lesson,
:presence => true,
:inclusion => {
:in => 1..9,
:message => "should have 1..9 symbols"
}
validates :tt_room,
:length => {
:maximum => 3,
:message => "should have 3 symbols"
},
:allow_blank => true
validates :tt_type,
:inclusion => { :in => ["Primary lesson", "Extra"] },
:allow_blank => true
validate :test
def test
errors.add(:tt_number_of_lesson, "test")
end
end
我的 Controller :
# encoding: UTF-8
class TimetablesController < ApplicationController
...
def edit
@types_of_lesson = collect_types_of_lesson
@tt = Timetable.find( params[:id] )
@subjects_with_curriculums = collect_subjects_with_curriculums( @tt.school_class )
end
def update
@tt = Timetable.find( params[:id] )
if @tt.update_attributes( params[:timetable] )
flash[:success] = "Расписание успешно обновлено!"
redirect_to timetables_path
else
flash.now[:error] = @tt.errors.full_messages.to_sentence :last_word_connector => ", ",
:two_words_connector => ", "
render 'edit'
end
end
private
# Collecting subjects names for school class and curriculum_id for each subject.
def collect_subjects_with_curriculums( school_class )
subjects = school_class.curriculums.collect do |c|
[ c.qualification.subject.subject_name, c.id ]
end
end
def timetable_for_class_with_existance_data( school_class )
return [] if Timetable.all.empty?
Timetable.select do |t|
( t.school_class.class_code == school_class.class_code ) and
not ( t.tt_room.blank? ) and not ( t.tt_type.blank? ) and
not ( t.curriculum_id.nil? )
end.to_a
end
# Return for school class it's timetable.
def timetable_for_class( school_class )
Timetable.select{|t| t.school_class.class_code == school_class.class_code }.to_a
end
def subjects_of_class( school_class )
subjects = school_class.curriculums.collect do |c|
c.qualification.subject.subject_name
end
end
# Return sorted by number of lesson tometable for one day.
def sorted_timetable_for_day( timetable, day )
timetable.select{ |t| t.tt_day_of_week == day }
.sort_by{ |e| e[:tt_number_of_lesson] }
end
# Return russian name for type of lesson.
def collect_types_of_lesson
[ ["Обязательно занятие", "Primary lesson"], ["Электив", "Extra"] ]
end
# Check if timetable already has been created for school class.
def timetable_exists?( school_class )
not timetable_for_class( school_class ).empty?
end
end
我的看法
<%= form_for @tt, :html => {:class => "form-horizontal"} do |f| %>
<%= field_set_tag do %>
<%= f.hidden_field :tt_number_of_lesson %>
<%= f.hidden_field :tt_day_of_week %>
<%= f.hidden_field :school_class_id %>
<div class="control-group">
<%= f.label :tt_day_of_week, "Day of the week", :class => "control-label" %>
<div class="controls">
<%= content_tag( :span, translate_day_of_week( @tt.tt_day_of_week ),
:class =>"input-xlarge uneditable-input span2" ) %>
</div>
</div>
<div class="control-group">
<%= f.label :tt_number_of_lesson, "Number of lesson", :class => "control-label" %>
<div class="controls">
<%= content_tag( :span, @tt.tt_number_of_lesson,
:class =>"input-xlarge uneditable-input span1" ) %>
</div>
</div>
<hr/>
<div class="control-group">
<%= f.label :curriculum_id, "Type of subject", :class => "control-label" %>
<div class="controls">
<%= f.select( :curriculum_id,
options_for_select( @subjects_with_curriculums,
@tt.curriculum_id ),
{ :include_blank => true }) %>
</div>
</div>
<div class="control-group">
<%= f.label :tt_room, "Code of the room", :class => "control-label" %>
<div class="controls">
<%= f.text_field :tt_room, :class => "span2", :maxlength => 3 %>
</div>
</div>
<div class="control-group">
<%= f.label :tt_type, "Type of the lesson", :class => "control-label" %>
<div class="controls">
<%= f.select( :tt_type,
options_for_select( @types_of_lesson,
@tt.tt_type ),
{ :include_blank => true }) %>
</div>
</div>
<%= f.submit "Update", :class => "btn btn-large btn-warning" %>
<% end %>
<% end %>
当我删除时:
<div class="control-group">
<%= f.label :curriculum_id, "Type of subject", :class => "control-label" %>
<div class="controls">
<%= f.select( :curriculum_id,
options_for_select( @subjects_with_curriculums,
@tt.curriculum_id ),
{ :include_blank => true }) %>
</div>
</div>
<div class="control-group">
<%= f.label :tt_type, "Type of the lesson", :class => "control-label" %>
<div class="controls">
<%= f.select( :tt_type,
options_for_select( @types_of_lesson,
@tt.tt_type ),
{ :include_blank => true }) %>
</div>
</div>
我可以查看我的测试错误。我不知道发生了什么。
最佳答案
你在你的 update
Controller 中这样说:
render 'edit'
这只是告诉 Rails 渲染编辑模板,它不运行任何与 edit
Controller 关联的代码,它只是渲染 edit.html.erb
在当前上下文中。
来自Layouts and Rendering in Rails Guide :
2.2.2 Rendering an Action’s View
[some stuff aboutrender 'x'
,render :x
, andrender :action => :x
being the same...]Using
render
with:action
is a frequent source of confusion for Rails newcomers. The specified action is used to determine which view to render, but Rails does not run any of the code for that action in the controller. Any instance variables that you require in the view must be set up in the current action before callingrender
.
特别注意最后一句话:
Any instance variables that you require in the view must be set up in the current action before calling
render
.
您正在 edit
Controller 中设置 @subjects_with_curriculums
但使用 update
Controller 中的 edit
View .结果是 @subjects_with_curriculums
是 nil
当 edit.html.erb
尝试使用它时 update
尝试使用它呈现编辑 View 。
您需要在您的更新
Controller 中设置@subjects_with_curriculums
,您可能还需要@types_of_lesson
。
关于ruby-on-rails - Rails 3 - 未定义方法 `map' 为 nil :NilClass for my own validation,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/10971138/