I started to learn Rspec one day ago. When writing test for my articles controller, I got error at create new article. Here is my controller:
def create
Article.transaction do
begin
#article = Article.new(article_params)
respond_to do |format|
if #article.save
view_context.create_sitemap
flash[:show_alert] = true
format.html { redirect_to edit_admin_article_path(#article), notice: 'Created sucessfull' }
else
format.html { render :new }
format.json { render json: #article.errors,notice: "Unprocessable entity" }#may need a helper to handle exception
end
end
rescue Exception => e
raise ActiveRecord::Rollback
respond_to do |format|
flash[:show_alert] = true
format.html { redirect_to new_admin_article_path, notice: 'Create failed'}
end
end
end
end
here is my test:
describe "POST #create" do
context "with valid attributes" do
it "creates a new article" do
expect{
post :create, params: { article: FactoryGirl.attributes_for(:article) }
}.to change(Article, :count).by(1)
end
it "redirects to the index page" do
post :create, params: { article: FactoryGirl.attributes_for(:article) }
expect(response).to redirect_to admin_articles_path
end
end
context "with invalid attributes" do
it "does not save the new article" do
expect{
post :create, params: { article: FactoryGirl.attributes_for(:article) }
}.to_not change(Article, :count).by(1)
end
it "re-renders the :new template" do
post :create, params: { article: FactoryGirl.attributes_for(:article) }
expect(response).to render_template :new
end
end
end
And here is the log:
3) Admin::ArticlesController POST #create with valid attributes creates a new article
Failure/Error:
expect{
post :create, params: { article: FactoryGirl.attributes_for(:article) }
}.to change(Article, :count).by(1)
expected #count to have changed by 1, but was changed by 0
# ./spec/controllers/admin/articles_controller_spec.rb:29:in `block (4 levels) in <top (required)>'
I spent time to search for the same issue but, all of them didn't solve my error. My problem is I cannot find out where the error come from. Any help is appreciated.
Related
I am a new programmer on ruby on rails, and i have problem when upload picture. Deos anyone can help me. thanks in advance.
class StudentsController < ApplicationController
before_action :set_student, only: [:show, :edit, :update, :destroy]
# GET /students
# GET /students.json
def index
#students = Student.all
end
# GET /students/1
# GET /students/1.json
def show
end
# GET /students/new
def new
#student = Student.new
end
# GET /students/1/edit
def edit
end
# POST /students
# POST /students.json
def create
#student = Student.create(student_params)
respond_to do |format|
if #student.save
format.html { redirect_to #student, notice: 'Student was successfully created.' }
format.json { render :show, status: :created, location: #student }
else
format.html { render :new }
format.json { render json: #student.errors, status: :unprocessable_entity }
end
end
end
private
#def student_params
#params.require(:student).permit(:image_file)
#end
# PATCH/PUT /students/1
# PATCH/PUT /students/1.json
def update
respond_to do |format|
if #student.update(student_params)
format.html { redirect_to #student, notice: 'Student was successfully updated.' }
format.json { render :show, status: :ok, location: #student }
else
format.html { render :edit }
format.json { render json: #student.errors, status: :unprocessable_entity }
end
end
end
# DELETE /students/1
# DELETE /students/1.json
def destroy
#student.destroy
respond_to do |format|
format.html { redirect_to students_url, notice: 'Student was successfully destroyed.' }
format.json { head :no_content }
end
end
private
# Use callbacks to share common setup or constraints between actions.
def set_student
#student = Student.find(params[:id])
end
# Never trust parameters from the scary internet, only allow the white list through.
def student_params
params.require(:student).permit(:name, :gender, :telephone, :address)#, :image_file
end
end
Can't really find a problem in your post. It's a bit hard to understand. Did you follow the docs on https://github.com/thoughtbot/paperclip? I take it your file attachment is in the Student model?
params.require(:student).permit(:name, :gender, :telephone, :address)#, :image_file
now you only permit to save name, gender, telephone and address, the image file wil not be saved. You still have to permit it.
I'm trying to write a Rspec test for my nested autolinks_controller. However, the redirect after my create action is broken. After successfully creating an autolink I want to be redirected to that autolink within a particular website (hence, website_autolink_path). My controller spec looks like this:
describe "POST create when params[:website_id] are present" do
before(:each) do
#website = create(:website)
#autolink = attributes_for(:website_autolink, website_id: #website.id)
end
context "with valid attributes and params[:website_id] are present" do
it "saved the autolink in the database" do
expect{
post :create, website_id: #website, autolink: attributes_for(:website_autolink)
}.to change(Autolink, :count).by(1)
end
it "redirects to the 'index' page" do
post :create, website_autolink: #autolink, website_id: #website
response.should redirect_to website_autolink_path
end
end
end
This line is not working:
response.should redirect_to website_autolink_path
Giving me the error message:
ActionController::RoutingError:
No route matches {:action=>"show", :controller=>"autolinks"}
My factories look like this:
Autolink:
FactoryGirl.define do
factory :website_autolink do
name "MyName"
url "http://www.myurl.nl"
association :website
end
end
Website:
FactoryGirl.define do
factory :website do
name "Test"
domain "http://www.test.nl"
end
end
My AutolinkController:
def create
if params[:website_id].present?
#website = Website.find(params[:website_id])
#autolink = #website.autolinks.create(params[:autolink])
else
#autolink = Autolink.new(params[:autolink])
end
respond_to do |format|
if #autolink.save
if params[:website_id].present?
format.html { redirect_to [#website, #autolink], notice: "Autolink is met succes aangemaakt." }
else
format.html { redirect_to autolinks_path, notice: "Autolink is met succes aangemaakt." }
end
format.json { head :no_content }
else
format.html { render action: "new" }
format.json { render json: #autolink.errors, status: :unprocessable_entity }
end
end
end
Within my controller, the following line is the one I want to simulate using Rspec:
format.html { redirect_to [#website, #autolink], notice: "Autolink is met succes aangemaakt." }
In my localhost it's all working, but writing the actual test for this nested route troubles me.
I just found a solution for my problem. My controller spec for the create action now looks like this:
describe "POST create when params[:website_id] are present" do
context "with valid attributes and params[:website_id] are present" do
before(:each) do
#website = create(:website)
#autolink = attributes_for(:website_autolink, website: #website)
end
it "saved the autolink in the database" do
expect{
post :create, autolink: #autolink, website_id: #website.id
}.to change(Autolink, :count).by(1)
end
it "redirects to the 'index' page" do
post :create, autolink: #autolink, website_id: #website.id
response.should redirect_to website_autolink_path(#website, assigns(:autolink))
end
end
end
I just had to assign my autolink in order to redirect_to the nested path. Without it, the id of my autolink couldn't be found.
I have the following rspec test:
def valid_attributes
{ "product_id" => "1" }
end
describe "POST create" do
describe "with valid params" do
it "creates a new LineItem" do
expect {
post :create, {:line_item => valid_attributes}, valid_session #my valid_session is blank
}.to change(LineItem, :count).by(1)
end
Which fails with this error:
1) LineItemsController POST create with valid params redirects to the created line_item
Failure/Error: post :create, {:line_item => valid_attributes}, valid_session
ActiveRecord::RecordNotFound:
Couldn't find Product without an ID
# ./app/controllers/line_items_controller.rb:44:in `create'
# ./spec/controllers/line_items_controller_spec.rb:87:in `block (4 levels) in <top (required)>'
This is my controller's create action:
def create
#cart = current_cart
product = Product.find(params[:product_id])
#line_item = #cart.line_items.build(:product => product)
respond_to do |format|
if #line_item.save
format.html { redirect_to #line_item.cart, notice: 'Line item was successfully created.' }
format.json { render json: #line_item.cart, status: :created, location: #line_item }
else
format.html { render action: "new" }
format.json { render json: #line_item.errors, status: :unprocessable_entity }
end
end
end
As you can see, my action expects a product_id from the request's params object. How should I work this product_id into my rspec test?
I've tried placing this before statement:
before(:each) do
ApplicationController.any_instance.stub(:product).and_return(#product = mock('product'))
end
. . . but it changes nothing. I am missing some rspec concept here somewhere.
Try like this:
describe "POST create" do
describe "with valid params" do
it "creates a new LineItem" do
expect {
post :create, :product_id => 1
}.to change(LineItem, :count).by(1)
end
Hope it helps.
I ended up resolving my issue by using a fixture instead of attempting to mock the solution as suggested in another answer.
The reason for this is that the controller does the query to get information from the database: product = Product.find(params[:product_id]) and I found a fixture-based solution was quicker to resolve my problem than one using a mock and I could not figure out how to stub the query quickly (the fixtures also help with another test on the controller so it eventually helped anyway.
For reference:
I referenced my fixture with this line toward the top of the test: fixtures :products
I changed my test to:
describe "POST create" do
describe "with valid params" do
it "creates a new LineItem" do
expect {
post :create, :product_id => products(:one).id
}.to change(LineItem, :count).by(1)
end
And here is my fixture file, products.yml:
one:
name: FirstProduct
price: 1.23
two:
name: SecondProduct
price: 4.56
I'm trying to test a controller with a name space, following is my controller (/admin/sites_controller.rb):
class Admin::SitesController < AdminController
def create
#site = Site.new(params[:site])
respond_to do |format|
if #site.save
format.html { redirect_to(#site, :notice => 'Site was successfully created.') }
format.xml { render :xml => #site, :status => :created, :location => #site }
else
format.html { render :action => "new" }
format.xml { render :xml => #site.errors, :status => :unprocessable_entity }
end
end
end
end
and following is my routes.rb file
namespace :admin do
resources :sites
end
I'm using rspec2 to test my controller and following is my controller spec
describe Admin::SitesController do
describe "POST create" do
describe "with valid params" do
it "creates a new Site" do
expect {
post :create, :site => valid_attributes
}.to change(Site, :count).by(1)
end
end
end
end
But when I run the spec it gives me the following routing error
Admin::SitesController POST create with valid params creates a new Site
Failure/Error: post :create, :site => valid_attributes
NoMethodError:
undefined method `site_url' for #<Admin::SitesController:0xb5fbe6d0>
# ./app/controllers/admin/sites_controller.rb:47:in `create'
# ./app/controllers/admin/sites_controller.rb:45:in `create'
# ./spec/controllers/admin/sites_controller_spec.rb:78
# ./spec/controllers/admin/sites_controller_spec.rb:77
I guess its because of the 'admin' name space I'm using, but how can I fix that?
I'm using
Rails3
Rspec2
Linux
When you namespace the route, you're creating URL and path helpers that look like this:
HTTP Verb Path action helper
GET /admin/sites index admin_sites_path
GET /admin/sites/new new new_admin_site_path
POST /admin/sites create admin_sites_path
GET /admin/sites/:id show admin_site_path(:id)
GET /admin/sites/:id/edit edit edit_admin_site_path(:id)
PUT /admin/sites/:id update admin_site_path(:id)
DELETE /admin/sites/:id destroy admin_site_path(:id)
So you can either use those directly in your code (i.e. redirect_to admin_site_path(#site) ), or you can do something like:
redirect_to([:admin, #site])
I'm a newbie in RSpec, I have this controller in my ruby on rails code
def create
#article = current_user.articles.build params[:article]
if #article.save
redirect_to articles_path, :notice => 'Article saved successfully!'
else
render :new
end
end
How would you test this action in RSpec ?
Thank you
describe "POST 'create'" do
let(:article) { mock_model(Article) }
before(:each) do
controller.stub_chain(:current_user,:articles,:build) { article }
end
context "success" do
before(:each) do
article.should_receive(:save).and_return(true)
post :create
end
it "sets flash[:notice]" do
flash[:notice].should == "Article saved successfully!"
end
it "redirects to articles_path" do
response.should redirect_to(articles_path)
end
end
context "failure" do
before(:each) do
article.should_receive(:save).and_return(false)
post :create
end
it "assigns #article" do
assigns(:article).should == article
end
it "renders new" do
response.should render_template('new')
end
end
end