2

私は非常に奇妙な問題に遭遇しました。モデルがTimetableあり、カスタム検証を作成しようとしています。だから、今私はすべてが大丈夫であることを確認するためにフィールドのテストエラーを追加しようとしています。しかし、それは機能しません。したがって、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 

私のコントローラー:

# 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>

テストエラーを表示できます。何が起こっているのか理解できません。

4

1 に答える 1

6

あなたはあなたのupdateコントローラーでこれを言います:

render 'edit'

editこれは、Railsに編集テンプレートをレンダリングするように指示するだけで、コントローラーに関連付けられたコードを実行せずedit.html.erb、現在のコンテキストでレンダリングするだけです。

Railsガイドのレイアウトとレンダリングから:

2.2.2アクションのビューのレンダリング[、、、および同じで
あることに関するいくつかのこと...] render 'x'render :xrender :action => :x

renderwithを使用する:actionことは、Railsの初心者にとって頻繁な混乱の原因です。指定されたアクションは、レンダリングするビューを決定するために使用されますが、Railsはコントローラーでそのアクションのコードを実行しません。ビューで必要なインスタンス変数は、を呼び出す前に現在のアクションで設定する必要がありますrender

最後の文に特に注意してください:

ビューで必要なインスタンス変数は、を呼び出す前に現在のアクションで設定する必要がありますrender

コントローラで設定@subjects_with_curriculumsしていますが、コントローラからのビューeditを使用しています。その結果、編集ビューをレンダリングしようとしたときに使用しようとします。editupdate@subjects_with_curriculumsniledit.html.erbupdate

コントローラで設定する必要があります@subjects_with_curriculums。必要になる場合もあります。update@types_of_lesson

于 2012-06-10T18:49:19.303 に答える