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.
Related
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.
I am using devise for user sign up/in. But when user signs in from public accessible pages, devise redirects to root_path.
I tried to use this:
def after_sign_in_path_for(resource)
request.referrer
end
When user tries to sign in, it gives error 'not redirected properly'.
Can anybody tell how to do it?
I believe if I am right what you want to do is override the redirect when a user sign in is to change the following method inside controllers/devise/sessions_controller.rb If you haven't generated devises controllers you generate devise controller. Having done that you will want to have something like the following inside your devise/sessions_controller.rb
def create
self.resource = warden.authenticate!(auth_options)
set_flash_message(:notice, :signed_in) if is_navigational_format?
sign_in(resource_name, resource)
# respond_with resource, :location => after_sign_in_path_for(resource)
if current_user.role? :administrator
redirect_to dashboard_path
else
redirect_to rota_days_path
end
end
In the above example by default the sessions_controller - create method uses the following: # respond_with resource, :location => after_sign_in_path_for(resource) which I have commented out. By adding a if statement that checks if the current_users role is an administrator. If they then they are redirected to the dashboard page. If not then they are redirected to the rota page.
Alternatively the devise helpers state that you could also do something like:
def after_sign_in_path_for(resource)
stored_location_for(resource) ||
if resource.is_a?(User) && resource.can_publish?
publisher_url
else
super
end
end
Hope this helps.
Update
def create
#hospital_booking = HospitalBooking.new(params[:hospital_booking])
respond_to do |format|
if #hospital_booking.save
format.html { redirect_to :back, notice: 'Photographer Shift was successfully created.' }
format.json { render json: #hospital_booking, status: :created, location: #hospital_booking }
else
format.html { render action: 'new' }
format.json { render json: #hospital_booking.errors, status: :unprocessable_entity }
end
end
end
What happens here is when the hospital_booking is saved it redirects back to the issue page instead of redirecting to another page. Further reading here: api dock- redirect_to
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 am testing a controller in RSpec2 and for both my create and update actions, when passed invalid params, the controller should render either the "new" or "edit" templates respectively. It is doing that, but my test never passes.
describe "with invalid params" do
before(:each) do
User.stub(:new) { mock_user(:valid? => false, :save => false) }
end
it "re-renders the 'new' template" do
post :create, :company_id => mock_company.id
response.should render_template("new")
end
end
Results in this:
re-renders the 'new' template
expecting <"new"> but rendering with <"">
Here is the controller action:
respond_to do |format|
if #user.save
format.html {
flash[:notice] = "#{#user.full_name} was added to #{#company.name}."
redirect_to company_users_url(#company)
}
else
logger.debug #user.errors
format.html{
render :new
}
end
end
This problem also seems to be isolated to this controller. I have almost identical code running another controller and it is fine. I am not sure where the problem could be.
Update:
Here are the two mock methods
def mock_user(stubs={})
#mock_user ||= mock_model(User, stubs).as_null_object
end
def mock_company(stubs={})
(#mock_company ||= mock_model(Company).as_null_object).tap do |company|
company.stub(stubs) unless stubs.empty?
end
end
Turned out it was a problem with stubbing and CanCan. CanCan was loading the resources and uses some different methods than what I thought.
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