ruby-on-rails - Rails 3 - 未定义方法 `map' 为 nil :NilClass for my own validation

标签 ruby-on-rails ruby ruby-on-rails-3

我遇到了一个很奇怪的问题。我有 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 about render 'x', render :x, and render :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 calling render.

特别注意最后一句话:

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_curriculumsniledit.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/

相关文章:

ruby-on-rails-3 - Rails 控制台 - 向上箭头不适用于最后一个命令

ruby-on-rails - 使用 each_with_index 循环时如何将索引合并到变量名中?

Ruby - 访问多维哈希并避免访问 nil 对象

ruby - 如何通过viddl-rb下载视频?

ruby-on-rails - 使用 Capistrano 运行同步或异步任务

jquery - will_paginate + 无限滚动插件 - 不显示 "Loading"消息

ruby-on-rails - 为什么每个人都使用双引号而不是单引号?

ruby-on-rails - 在登录或注册后设计重定向回原始位置?

mysql - 我的测试应该为强制关联创建数据库记录吗?

ruby-on-rails - Heroku 正在为 Rails 5 应用程序提供旧 Assets