RSpec - 无法获取控制器中的所有关联属性

时间:2016-09-17 20:44:42

标签: ruby-on-rails ruby ruby-on-rails-4 web-applications rspec

Hello Programmers&开发人员!!!,我是RoR的初学者并在rails中创建一个简单的项目来学习它的工作,所以在那个项目中,我在编写create方法的规范时遇到了问题。控制器。当我试图在spec文件中传递对象的关联属性时,在控制器中它不会获得所有属性。

create文件的subjects_controller.rb方法中。我已在此变量中创建了一个名为attr的变量I' m存储从subjects_controller_spec.rb文件发送的所有值。

attr=(params.require(:subject).permit(:name)).merge(:classroom_ids=>params[:subject][:classroom_ids],:school_ids=>params[:subject][:school_ids])

现在,如果我在控制台中使用attr打印p attr的值,它的输出就是我想要的确切输出,这是

{"name"=>"Computer", "classroom_ids"=>["1", "2"], "school_ids"=>["1"]}

但是,现在我正在执行@subject = Subject.new(attr)并且@subject的打印值提供以下输出

#<Subject id: nil, name: "Computer", created_at: nil, updated_at: nil>

在运行测试后,我的测试失败,然后我打印错误p @subject.errors它给了我以下输出

#<ActiveModel::Errors:0x007fc35444a218 @base=#<Subject id: nil, name: "Computer", created_at: nil, updated_at: nil>, @messages={:school_ids=>["is not a number"], :classroom_ids=>["is not a number"]}>

所以,这是我的实际问题,为什么@subject中的 subjects_controller.rb 没有 classroom_ids 的值和 school_ids ?如果有任何解决方案或建议,请帮我解决这个问题。



在下面我提供了解实际问题所需的所有细节

Ruby版本 2.2.4
Rails版本 4.2.0
数据库 MySQL

模型文件 subject.rb

class Subject < ActiveRecord::Base
  has_and_belongs_to_many :schools
  has_and_belongs_to_many :teachers
  has_and_belongs_to_many :classrooms
  has_and_belongs_to_many :students

  validates_presence_of :name, :school_ids, :classroom_ids
  validates_numericality_of :school_ids, :classroom_ids
end



控制器文件 subjects_controller_spec.rb

require 'rails_helper'

RSpec.describe SubjectsController, type: :controller do
  before(:each) do
    @school1 = FactoryGirl.create(:school)
    @classroom1 = FactoryGirl.create(:classroom, :school_id=>@school1.id)
    @classroom2 = FactoryGirl.create(:classroom, :school_id=>@school1.id)
    @subject = FactoryGirl.build(:subject)
    @subject.classrooms<<@classroom1
    @subject.classrooms<<@classroom2
    @subject.schools<<@school1
  end
  context "POST create" do
    it "should be success" do
      # p @subject
      # p @subject.classrooms
      # p @subject.classroom_ids
      attributes=@subject.attributes.merge(:classroom_ids=>@subject.classroom_ids,:school_ids=>@subject.school_ids)

      # In below line, I'm sending all the values to the controller to create a new subject.

      post :create, :subject=>attributes

      response.status.should eq 201
    end
  end
end



控制器文件 subjects_controller.rb

class SubjectsController < ApplicationController
  before_action :set_subject, only: [:show, :edit, :update, :destroy]

  # GET /subjects
  def index
    @subjects = Subject.all
  end

  # GET /subjects/1
  def show
  end

  # GET /subjects/new
  def new
    @subject = Subject.new
  end

  # GET /subjects/1/edit
  def edit
  end



  # POST /subjects
  def create
    attr=(params.require(:subject).permit(:name)).merge(:classroom_ids=>params[:subject][:classroom_ids],:school_ids=>params[:subject][:school_ids])

    p attr ### here it prints all the values which I want to create subject.###

    @subject = Subject.new(attr)

    p @subject ### here is the actual problem, It's not printing all the values that need to create a new subject.###

    if @subject.save
      redirect_to @subject, notice: 'Subject was successfully created.', status: :created
    else
      p @subject.errors
      render :new, status: :unprocessable_entity
    end
  end



  # PATCH/PUT /subjects/1
  def update
    if @subject.update(subject_params)
      redirect_to @subject, notice: 'Subject was successfully updated.', status: :ok
    else
      render :edit, :status => :unprocessable_entity
    end
  end

  # DELETE /subjects/1
  def destroy
    @subject.destroy
    redirect_to subjects_url, notice: 'Subject was successfully destroyed.'
  end

  private
    # Use callbacks to share common setup or constraints between actions.
    def set_subject
      @subject = Subject.find(params[:id])
    end

    # Only allow a trusted parameter "white list" through.
    def subject_params
      params.require(:subject).permit(:name, :school_ids, :classroom_ids)
    end
end

工厂档案 subjects.rb

FactoryGirl.define do
  factory :subject do
    name "Computer"
  end
end



RSpec 测试报告

rspec spec/controllers/subjects_controller_spec.rb 
{"name"=>"Computer", "classroom_ids"=>["1", "2"], "school_ids"=>["1"]}
#<Subject id: nil, name: "Computer", created_at: nil, updated_at: nil>
#<ActiveModel::Errors:0x007fcdfe8f1a28 @base=#<Subject id: nil, name: "Computer", created_at: nil, updated_at: nil>, @messages={:school_ids=>["is not a number"], :classroom_ids=>["is not a number"]}>
F

Failures:

  1) SubjectsController POST create should be success
     Failure/Error: response.status.should eq 201

       expected: 201
            got: 422

       (compared using ==)
     # ./spec/controllers/subjects_controller_spec.rb:21:in `block (3 levels) in <top (required)>'

Deprecation Warnings:

Using `should` from rspec-expectations' old `:should` syntax without explicitly enabling the syntax is deprecated. Use the new `:expect` syntax or explicitly enable `:should` with `config.expect_with(:rspec) { |c| c.syntax = :should }` instead. Called from /Users/vishal/project/school_system/spec/controllers/subjects_controller_spec.rb:21:in `block (3 levels) in <top (required)>'.


If you need more of the backtrace for any of these deprecations to
identify where to make the necessary changes, you can configure
`config.raise_errors_for_deprecations!`, and it will turn the
deprecation warnings into errors, giving you the full backtrace.

1 deprecation warning total

Finished in 0.40113 seconds (files took 3.03 seconds to load)
1 example, 1 failure

Failed examples:

rspec ./spec/controllers/subjects_controller_spec.rb:14 # SubjectsController POST create should be success

Coverage report generated for RSpec to /Users/vishal/project/school_system/coverage. 49 / 332 LOC (14.76%) covered.


有关详细信息,请参阅this Github link

先谢谢你的帮助。

1 个答案:

答案 0 :(得分:1)

[“1”,“2”]不是整数数组而是字符串! @subject具有classroom_ids和school_ids,但params始终将输入值视为String,因此在Subject模型中会出现验证错误。因此,请尝试以下将String转换为Integer:

params[:subject][:classroom_ids].map(&:to_i) 
params[:subject][:school_ids].map(&:to_i) 

这个怎么样?

在控制器中没有map方法的情况下恢复如下:

params[:subject][:classroom_ids] 
params[:subject][:school_ids]

在我的电脑中,通过从github链接修改下面的主题模型并通过测试。 你能试试吗?

Class Subject < ActiveRecord::Base
  has_and_belongs_to_many :schools
  has_and_belongs_to_many :teachers
  has_and_belongs_to_many :classrooms
  has_and_belongs_to_many :students

  validates_presence_of :name, :school_ids, :classroom_ids
  validate :validate_classroom_ids
  validate :validate_school_ids

  private

  def validate_classroom_ids
    if classroom_ids.any?{ |id| !id.is_a?(Integer) }
      errors.add(:classroom_ids, 'is not a number')
      return false
    end
  end

  def validate_school_ids
    if school_ids.any?{ |id| !id.is_a?(Integer) }
      errors.add(:school_ids, 'is not a number')
      return false
    end
  end
end