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。
先谢谢你的帮助。
答案 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