我有一个令人困惑的rSpec问题-取决于我如何编写代码,描述"失败"规范的测试失败,或者描述"成功"规范的检测失败。
以下是创建操作的测试:
describe "POST 'create'" do
describe "failure" do
before(:each) do
@attr = {name: "", type_of_group: ""}
@student_attr = [{name: "Joe", gender: "Male"}, {name: "sally twotrees", gender: "Female"}]
@create = post :create, student_group: @attr, student: @student_attr
end
it "should have the right title" do
@create
response.should have_selector('title', :content => "Create a new group" )
end
it "should render the 'new' page" do
@create
response.should render_template('new')
end
it "should not create a user" do
lambda do
post :create, student_group: @attr
end.should_not change {@user.student_groups.count}
end
it "should flash an error message" do
@create
flash[:error].should =~ /please/i
end
end
describe "success" do
before(:each) do
@attr = FactoryGirl.attributes_for(:student_group)
# @student_attr = {name: "test", gender: "Male"}
end
it "should create a student_group" do
lambda do
post :create, student_group: @attr
end.should change {@user.student_groups.count}.by(1)
end
it "should create students" # do
# lambda do
# post :create, student_group: @attr, student: @student_attr
# end.should change {@student_groups.students.count}.by(1)
# end
it "should flash a success message" do
post :create, student_group: @attr
flash[:success].should =~ /has been added/i
end
it "should redirect" do
post :create, student_group_id: @group, student_group: @attr
response.should be_redirect
end
end
end
所有"失败"测试都失败,并出现以下错误:
Failure/Error: @create = post :create, student_group: @attr, student: @student_attr
ActionView::Template::Error:
`@student_group[students_attributes]' is not allowed as an instance variable name
如果我在控制器中这样写代码:
def create
@params = params[:student_group][:students_attributes]
@student_group = @user.student_groups.build(params[:student_group])
if @student_group.save
### RE: 'defensive coding' https://stackoverflow.com/questions/14502508/undefined-method-for-nilnilclass-when-pushing-values-to-an-array
if @params.present?
### https://stackoverflow.com/questions/11355820/rails-3-2-iterate-through-an-array
@params.each do |student|
@student_group.students.create(name:"#{student[:name]}", gender: "#{student[:gender]}")
end
end
# new subject path
redirect_to class_path(@student_group), flash: { success: "#{@student_group.name} has been added successfully" }
else
@title = "Create a new group"
flash.now[:error] = "Something's gone wrong. Please try again!"
render 'new'
end
end
如果控制器代码是这样写的,那么所有的"成功"测试都会失败:
def create
@params = params[:student_group][:students_attributes]
@student_group = @user.student_groups.build(params[:student_group])
### http://railsforum.com/viewtopic.php?pid=40056#p40056
if @params.present?
@student = Student.new
else
@student = @student_group.students.build(@params)
end
if @student_group.save
### RE: 'defensive coding' https://stackoverflow.com/questions/14502508/undefined-method-for-nilnilclass-when-pushing-values-to-an-array
if @params.present?
### https://stackoverflow.com/questions/11355820/rails-3-2-iterate-through-an-array
@params.each do |student|
@student_group.students.create(name:"#{student[:name]}", gender: "#{student[:gender]}")
end
end
# new subject path
redirect_to class_path(@student_group), flash: { success: "#{@student_group.name} has been added successfully" }
else
@title = "Create a new group"
flash.now[:error] = "Something's gone wrong. Please try again!"
render 'new'
end
end
表单代码如下:https://stackoverflow.com/a/17591802/2128691
从上面的代码来看,您的控制器代码似乎真的一团糟。在嵌套属性的情况下,您只需要保存父对象。如果子对象有效,则会自动保存这些子对象。此外,您不需要将params分配给某个实例对象。它们应该直接使用。嵌套属性的一个简单示例可以是
User
has_many :comments
accepts_nested_attributes_for :comments
Comment
belongs_to :user
ur控制器代码应为
def create
@user = User.new(params[:user])
if @user.save
flash[:notice] = 'success'
redirect_to some_path and return
end
render 'new'
end
rspec控制器测试用例可以是
it "should create a user with comments if valid data is provided" do
post :create, "user"=>{"name"=>"Prasad", "comments_attributes"=>{"0"=>{"comment"=>"first comment"}, "1"=>{"comment"=>"second comment"}}, "commit"=>"Save"
user = assigns[:user] #assigns lets u access the instance variable from the controller in the spec
user.should be_valid
user.comments.count.should == 2 #check that all the child models are saved
user.name.should == "Prasad"
user.comments.first.comment.should == 'first comment'
user.comments.last.comment.should == 'second comment'
response.should be_redirect(some_path) #since u redirected in the code
end
说真的,你需要通过导轨。
我最终使用了以下代码:
def create
@student_group = @user.student_groups.new(params[:student_group])
@params = params[:student_group][:students_attributes]
@student_group = @user.student_groups.build(params[:student_group])
if @student_group.save
### RE: 'defensive coding' http://stackoverflow.com/questions/14502508/undefined-method-for-nilnilclass-when-pushing-values-to-an-array
if @params.present?
### http://stackoverflow.com/questions/11355820/rails-3-2-iterate-through-an-array
@params.each do |student|
@student_group.students.create(name:"#{student[:name]}", gender: "#{student[:gender]}")
end
end
redirect_to new_student_group_subject_path(@student_group), flash: { success: "#{@student_group.name} has been added successfully. Next, add the subjects for this group" }
else
### http://railsforum.com/viewtopic.php?pid=40056#p40056
@student = @student_group.students.build
@title = "Create a new group"
flash.now[:error] = "Something's gone wrong. Please try again!"
render 'new'
end
end