Tengo una aplicación Rails (Rails 3.0.10) donde los usuarios pueden tener muchos artículos, y donde los usuarios pueden dejar comentarios sobre los artículos. Los comentarios se hacen en la página de la demostración del artículo.Prueba RSpec para crear la acción de un controlador para un recurso anidado
Ahora quiero probar la acción create del CommentsController, sin embargo, tengo problemas para invocar el método post con los parámetros correctos.
Aquí está el código de la CommentsController:
class CommentsController < ApplicationController
# create a comment and bind it to an article and a user
def create
@article = Article.find(params[:article_id])
@user = User.find(@article.user_id)
@comment = @article.comments.build(params[:comment])
@comment.user_id = current_user.id
commenters = []
@article.comments.each {
|comment|
commenters << User.find(comment.user_id)
}
commenters.uniq!
respond_to do |format|
if @comment.save
#Notify user who offers article on new comment, else notify the commenters
if @article.user_id != @comment.user_id
UserMailer.new_article_comment_email(@user, @comment).deliver
else
commenters.each {
|commenter|
UserMailer.new_article_comment_email(commenter, @comment).deliver
}
end
format.html {
redirect_to(@article)
flash[:notice] = t(:comment_create_success)
}
else
format.html {
redirect_to(@article)
flash[:error] = t(:comment_create_error)
}
end
end
end
end
El código RSpec para probar esta acción (algunos experimentos hasta ahora) es la siguiente:
require 'spec_helper'
require 'ruby-debug'
describe CommentsController do
render_views
describe "POST 'create'" do
before(:each) do
@user = FactoryGirl.create(:user)
@article = FactoryGirl.build(:article)
@article.user_id = @user.id
@article.save
@article_attributes = FactoryGirl.attributes_for(:article)
@comment_attributes = FactoryGirl.attributes_for(:comment)
end
it "should create a new comment" do
expect {
post :create, :comment => @comment_attributes
}.to change(Comment, :count).by(1)
end
it "should create a new comment, redirect to the article show page of this comment and notify the user on successful saving of the comment" do
post :create, :comment => @comment_attributes, :article_id => @article.id.to_s, :user_id => @user.id.to_s
flash[:notice].should_not be_nil
response.should redirect_to(article_path(@article))
end
end
end
Ambas pruebas fallan, sin embargo, debido a razones diferentes que no puedo solucionar:
Failures:
1) CommentsController POST 'create' should create a new comment
Failure/Error: post :create, :comment => @comment_attributes
ActionController::RoutingError:
No route matches {:comment=>{:body=>"This is the body text of a comment"}, :controller=>"comments", :action=>"create"}
# ./spec/controllers/comments_controller_spec.rb:22:in `block (4 levels) in <top (required)>'
# ./spec/controllers/comments_controller_spec.rb:21:in `block (3 levels) in <top (required)>'
2) CommentsController POST 'create' should create a new comment, redirect to the article show page of this comment and notify the user on successful saving of the comment
Failure/Error: post :create, :comment => @comment_attributes, :article_id => @article.id.to_s, :user_id => @user.id.to_s
RuntimeError:
Called id for nil, which would mistakenly be 4 -- if you really wanted the id of nil, use object_id
# ./app/controllers/comments_controller.rb:8:in `create'
# ./spec/controllers/comments_controller_spec.rb:27:in `block (3 levels) in <top (required)>'
Estaría genial si alguien podría ayudarme. ¡Gracias por adelantado!
Actualización: Aquí está la routes.rb estoy usando:
Cinderella::Application.routes.draw do
# The priority is based upon order of creation:
# first created -> highest priority.
# Sample of regular route:
# match 'products/:id' => 'catalog#view'
# Keep in mind you can assign values other than :controller and :action
# Sample of named route:
# match 'products/:id/purchase' => 'catalog#purchase', :as => :purchase
# This route can be invoked with purchase_url(:id => product.id)
match '/signup', :to => 'users#new'
match '/signin', :to => 'sessions#new'
match '/signout', :to => 'sessions#destroy'
match '/home', :to => 'pages#home'
match '/about', :to => 'pages#about'
match '/faq', :to => 'pages#faq'
match '/howitworks_sellers', :to => "pages#howitworks_sellers"
match '/howitworks_buyers', :to => "pages#howitworks_buyers"
match '/contact', :to => 'pages#contact'
match '/articles/:id/ratings', :to => 'ratings#destroy'
# Sample resource route (maps HTTP verbs to controller actions automatically):
# resources :products
resources :articles do
resources :comments, :only => [:create, :destroy]
end
resources :ratings
resources :ratings do
collection do
post 'destroy'
end
end
resources :users do
resources :articles
end
resources :sessions, :only => [:new, :create, :destroy]
# Sample resource route with options:
# resources :products do
# member do
# get 'short'
# post 'toggle'
# end
#
# collection do
# get 'sold'
# end
# end
# Sample resource route with sub-resources:
# resources :products do
# resources :comments, :sales
# resource :seller
# end
# Sample resource route with more complex sub-resources
# resources :products do
# resources :comments
# resources :sales do
# get 'recent', :on => :collection
# end
# end
# Sample resource route within a namespace:
# namespace :admin do
# # Directs /admin/products/* to Admin::ProductsController
# # (app/controllers/admin/products_controller.rb)
# resources :products
# end
# You can have the root of your site routed with "root"
# just remember to delete public/index.html.
root :to => "pages#home"
# See how all your routes lay out with "rake routes"
# This is a legacy wild controller route that's not recommended for RESTful applications.
# Note: This route will make all actions in every controller accessible via GET requests.
# match ':controller(/:action(/:id(.:format)))'
end
#== Route Map
# Generated on 14 Dec 2011 14:24
#
# signin /signin(.:format) {:controller=>"sessions", :action=>"new"}
# signout /signout(.:format) {:controller=>"sessions", :action=>"destroy"}
# home /home(.:format) {:controller=>"pages", :action=>"home"}
# about /about(.:format) {:controller=>"pages", :action=>"about"}
# faq /faq(.:format) {:controller=>"pages", :action=>"faq"}
# articles GET /articles(.:format) {:action=>"index", :controller=>"articles"}
# POST /articles(.:format) {:action=>"create", :controller=>"articles"}
# new_article GET /articles/new(.:format) {:action=>"new", :controller=>"articles"}
# edit_article GET /articles/:id/edit(.:format) {:action=>"edit", :controller=>"articles"}
# article GET /articles/:id(.:format) {:action=>"show", :controller=>"articles"}
# PUT /articles/:id(.:format) {:action=>"update", :controller=>"articles"}
# DELETE /articles/:id(.:format) {:action=>"destroy", :controller=>"articles"}
# user_articles GET /users/:user_id/articles(.:format) {:action=>"index", :controller=>"articles"}
# POST /users/:user_id/articles(.:format) {:action=>"create", :controller=>"articles"}
# new_user_article GET /users/:user_id/articles/new(.:format) {:action=>"new", :controller=>"articles"}
# edit_user_article GET /users/:user_id/articles/:id/edit(.:format) {:action=>"edit", :controller=>"articles"}
# user_article GET /users/:user_id/articles/:id(.:format) {:action=>"show", :controller=>"articles"}
# PUT /users/:user_id/articles/:id(.:format) {:action=>"update", :controller=>"articles"}
# DELETE /users/:user_id/articles/:id(.:format) {:action=>"destroy", :controller=>"articles"}
# users GET /users(.:format) {:action=>"index", :controller=>"users"}
# POST /users(.:format) {:action=>"create", :controller=>"users"}
# new_user GET /users/new(.:format) {:action=>"new", :controller=>"users"}
# edit_user GET /users/:id/edit(.:format) {:action=>"edit", :controller=>"users"}
# user GET /users/:id(.:format) {:action=>"show", :controller=>"users"}
# PUT /users/:id(.:format) {:action=>"update", :controller=>"users"}
# DELETE /users/:id(.:format) {:action=>"destroy", :controller=>"users"}
# sessions POST /sessions(.:format) {:action=>"create", :controller=>"sessions"}
# new_session GET /sessions/new(.:format) {:action=>"new", :controller=>"sessions"}
# session DELETE /sessions/:id(.:format) {:action=>"destroy", :controller=>"sessions"}
# root /(.:format) {:controller=>"pages", :action=>"home"}
Actualización: Aquí está la modificación que hizo conforme a nmotts sugerencias:
require 'spec_helper'
require 'ruby-debug'
describe CommentsController do
render_views
describe "POST 'create'" do
before(:each) do
@user = FactoryGirl.create(:user)
@article = FactoryGirl.build(:article)
@article.user_id = @user.id
@article.save
@comment_attributes = FactoryGirl.attributes_for(:comment, :article_id => @article)
end
it "should create a new comment" do
post :create, :article_id => @article.id.to_s, :comment => @comment_attributes
end
end
end
Y la definición factorygirl para hacer comentarios:
factory :comment do
body "This is the body text of a comment"
article
end
Desafortunadamente, el código aún no está funcionando.
Por favor, publique sus rutas.rb – lucapette
Actualicé mi publicación con las rutas completas. rb –