Rspec: Controller specs for 2 level nested resources - ruby-on-rails

my routes.rb
namespace :magazine do
resources :pages do
resources :articles do
resources :comments
end
end
end
While writing controller specs for Comments:
describe "GET 'index'" do
before(:each) do
#user = FactoryGirl.create(:user)
#page = FactoryGirl.build(:page)
#page.creator = #user
#page.save
#article = FactoryGirl.create(:article)
#comment_attributes = FactoryGirl.attributes_for(:comment, :article_id => #article )
end
it "populates an array of materials" do
get :index, ??
#response.should be_success
assigns(:comments)
end
it "renders the :index view" do
get :index, ??
response.should render_template("index")
end
end
Any idea how to give the page and article reference to get :index ??
if I give : get :index, :article_id => #article.id
Error I get is below:
Failure/Error: get :index, :article_id => #article.id
ActionController::RoutingError:
No route matches {:article_id =>"3", :controller=>"magazine/comments"}

Your route requires at least two IDs: the comment's parent article, and the article's parent page.
namespace :magazine do
resources :pages do
resources :articles do
resources :comments
end
end
end
# => /magazine/pages/:page_id/articles/:article_id/comments
All parent IDs must be provided for this route to work:
it "renders the :index view" do
get :index, {:page_id => #page.id, :article_id => #article.id}
# [UPDATE] As of Rails 5, this becomes:
# get :index, params: {:page_id => #page.id, :article_id => #article.id}
response.should render_template("index")
end

With Rails 5 the params API changed:
get :index, params: { page_id: #page.id, article_id: #article.id }
https://relishapp.com/rspec/rspec-rails/v/3-7/docs/request-specs/request-spec#specify-managing-a-widget-with-rails-integration-methods

Related

No route matches {:controller=>"submissions"}

I get this error when I'm running a test that simply does get :index. Here is the test code:
class SubmissionsControllerTest < ActionController::TestCase
setup do
#submission = submissions(:one)
end
test "should get index" do
get :index
assert_response :redirect
# assert_not_nil assigns(:submissions)
end
I have a route set up for this controller though in my routes.rb file:
resources :courses do
resources :assignments do
get 'export', :controller => 'assignments', :action => 'export'
resources :memberships
resources :submissions do
resources :evaluations do
delete 'destroy', controller: 'reviews', action: 'destroy'
end
end
resources :questions do
resources :responses
resources :scales
end
resources :reviews do
get :assign_reviews, :on => :collection
post :edit_review, :on => :collection
end
end
end
Also, this is what I get for submissions routes when I run rake routes:
course_assignment_submissions GET /courses/:course_id/assignments/:assignment_id/submissions(.:format) submissions#index
POST /courses/:course_id/assignments/:assignment_id/submissions(.:format) submissions#create
new_course_assignment_submission GET /courses/:course_id/assignments/:assignment_id/submissions/new(.:format) submissions#new
edit_course_assignment_submission GET /courses/:course_id/assignments/:assignment_id/submissions/:id/edit(.:format) submissions#edit
course_assignment_submission GET /courses/:course_id/assignments/:assignment_id/submissions/:id(.:format) submissions#show
PUT /courses/:course_id/assignments/:assignment_id/submissions/:id(.:format) submissions#update
DELETE /courses/:course_id/assignments/:assignment_id/submissions/:id(.:format) submissions#destroy
And here is my code for the index action:
def index
if !current_user.instructor?(#course)
raise CanCan::AccessDenied.new("Not authorized!")
end
registrations = #course.registrations
#students = registrations.select{|r| !r.user.pseudo or #assignment.memberships.any?{|m| m.pseudo_user_id == r.user_id } }.map{|r| r.user }
respond_to do |format|
format.html # index.html.erb
format.json { render json: #students }
end
end
Does anyone know where this error could be coming from then?
Because your submissions controller is nested into assignments and assignments into courses you have to pass an :assignment_id and a :course_id into your get request.
So for example:
get :index, course_id: your_course, assignment_id: your_assignment

The action 'create' & 'destroy' could not be found for RelationshipsController

Im in the last chapter of Ruby on Rails tutorial by M.Hartl and I'm facing the problem with actions 'create' and 'destroy'
I already checked title of my all files. I receive errors during tests:
ERROR["test_should_unfollow_a_user_with_Ajax", FollowingTest, 2015-12-03 23:12:38 +0000] test_should_unfollow_a_user_with_Ajax#FollowingTest (1449184358.75s) AbstractController::ActionNotFound: AbstractController::ActionNotFound: The action 'destroy' could not be found for RelationshipsController
test/integration/following_test.rb:53:in `block (2 levels) in <class:FollowingTest>'
test/integration/following_test.rb:52:in `block in <class:FollowingTest>'
test/integration/following_test.rb:53:in `block (2 levels) in <class:FollowingTest>'
test/integration/following_test.rb:52:in `block in <class:FollowingTest>'
The same error is for create action.
relationships_controller.rb
class RelationshipsController < ApplicationController
before_action :logged_in_user
def create
#user = User.find(params[:followed_id])
current_user.follow(#user)
respond_to do |format|
format.html { redirect_to #user }
format.js
end
end
def destroy
#user = Relationship.find(params[:id]).followed
current_user.unfollow(#user)
respond_to do |format|
format.html { redirect_to #user }
format.js
end
end
end
routes.rb
Rails.application.routes.draw do
root 'static_pages#home'
get 'help' => 'static_pages#help'
get 'about' => 'static_pages#about'
get 'contact' => 'static_pages#contact'
get 'signup' => 'users#new'
get 'login' => 'sessions#new'
post 'login' => 'sessions#create'
delete 'logout' => 'sessions#destroy'
resources :users do
member do
get :following, :followers
end
end
resources :account_activations, only: [:edit]
resources :password_resets, only: [:new, :create, :edit, :update]
resources :microposts, only: [:create, :destroy]
resources :relationships, only: [:create, :destroy]
end
following_test.rb
require 'test_helper'
class FollowingTest < ActionDispatch::IntegrationTest
def setup
#user = users(:michael)
#other = users(:archer)
log_in_as(#user)
end
test "following page" do
get following_user_path(#user)
assert_not #user.following.empty?
assert_match #user.following.count.to_s, response.body
#user.following.each do |user|
assert_select "a[href=?]", user_path(user)
end
end
test "followers page" do
get followers_user_path(#user)
assert_not #user.followers.empty?
assert_match #user.followers.count.to_s, response.body
#user.followers.each do |user|
assert_select "a[href=?]", user_path(user)
end
end
test "should follow a user the standard way" do
assert_difference '#user.following.count', 1 do
post relationships_path, followed_id: #other.id
end
end
test "should follow a user with Ajax" do
assert_difference '#user.following.count', 1 do
xhr :post, relationships_path, followed_id: #other.id
end
end
test "should unfollow a user the standard way" do
#user.follow(#other)
relationship = #user.active_relationships.find_by(followed_id: #other.id)
assert_difference '#user.following.count', -1 do
delete relationship_path(relationship)
end
end
test "should unfollow a user with Ajax" do
#user.follow(#other)
relationship = #user.active_relationships.find_by(followed_id: #other.id)
assert_difference '#user.following.count', -1 do
xhr :delete, relationship_path(relationship)
end
end
end
Does anyone have any idea what's the problem? I checked other questions of this error and none of them are applicable to my application.
Many thanks in advance for help!

routes error in rails

I am working on a project. I am making an application where a user can add an issue (like a post) and the user can comment on it.
on running this application, I get an error
Couldn't find Issue with 'id'=show
the code for routes file is
resources :issues do
resources :comments
end
get 'users/new'
get 'users/create'
get 'users/show'
get 'users/edit'
get 'issues/show/:id', :to => 'issues#show'
resources :users
resources :sessions, :only => [:create, :new,:destroy]
get '/signup', :to => 'users#new'
get '/signin' , :to => 'sessions#new'
get '/signout', :to => 'sessions#destroy'
the code for the issues controller is
class IssuesController < ApplicationController
def new
#issue = Issue.new
end
def create
#issue = Issue.new(issues_params)
if #issue.save
flash[:success]='your issue has been raised'
redirect_to :controller => 'issues', :action => 'show', :id => #issue.id
else
render 'new'
end
end
def edit
#issue = Issue.find(params[:id])
end
def update
#issue = Issue.find(params[:id])
if #issue.update_attributes(issues_params)
redirect_to :controller => 'issues', :action => 'show', :id => #issue.id
else
render 'edit'
end
end
def index
#issues = Issue.all
end
def show
#issue = Issue.find(params[:id])
end
def destroy
#issue=Issue.find(params[:id])
#issue.destroy
redirect_to :controller => 'issues', :action => 'index'
end
protected
def issues_params
params.require(:issue).permit(:title,:content)
end
end
the code for the comments controller from where I call the show method in issues controller is
class CommentsController < ApplicationController
def create
#issue = Issue.find(params[:issue_id])
#comment = #issue.comments.create(comment_params)
if #comment.save
redirect_to :controller => 'issues', :action => 'show', :id => #issue[:id]
else
render 'new'
end
end
private
def comment_params
params.require(:comment).permit(:content)
end
end
You must be trying to request the URI /issues/show? This will map to the GET /issues/:id from the resources :issues do line of your routes. The router will set the params[:id] to the string "show" and send the request to the show action of the IssuesController which, as you've shown, will then try to do Issue.find(params[:id]) ie. Issue.find("show") and hence you get your error.
Change this
resources :issues do
resources :comments
end
to
resources :issues, except: [:show] do
resources :comments
end
It will resolve your problem!

Testing nested controllers: NoMethodError: undefined method `empty?' for nil:NilClass

I have been trying to get my controller test pass...
My routes.rb
namespace :school do
resource :account, :except => [:new, :create, :destroy], :controller => 'account'
resources :classes, :path => "" do
resources :discussions do
resources :comments
end
resources :materials
end
end
MY DiscussionController specs:
describe "POST 'create'" do
before(:each) do
#user = FactoryGirl.create(:coordinator_user)
login_user(#user)
#klass = FactoryGirl.build(:klass)
#klass.creator = #user
#klass.save
#parameters = FactoryGirl.attributes_for(:discussion, :klass_id => #klass, :user_id => #user)
end
context "with valid parameters" do
it "creates a new job" do
expect { post :create, :class_id => #klass.id, :discussion => #parameters }.to change(Discussion, :count).by(1)
end
it "should create a new discussion" do
post :create, :class_id => #klass.id
response.should be_redirect
response.should redirect_to(school_account_path(assigns(:discussion).id))
assigns(:discussion).should_not be_nil
assigns(:discussion).should_not be_new_record
end
end
I get errors: 1) NoMethodError: undefined method empty?' for nil:NilClass # ./lib/slug.rb:3:inslug'
Cannot understand what is nil here.

No route matches {:action=>"up_vote", :controller=>"votes", :post_id=>"1"}

I've been receiving the following error in my RSpec when trying to get my upvote method to pass:
Failures:
1) VotesController#up_vote adds an up-vote to the post
Failure/Error: post( :up_vote, post_id: #post.id )
ActionController::UrlGenerationError:
No route matches {:action=>"up_vote", :controller=>"votes", :post_id=>"1"}
Now I can upvote and downvote when I'm on the server, it's just my test that won't work.
Here's my code:
votes_controller_spec.rb
require 'rails_helper'
describe VotesController do
include TestFactories
include Devise::TestHelpers
describe '#up_vote' do
it "adds an up-vote to the post" do
request.env["HTTP_REFERER"] = '/'
#user = authenticated_user
#post = associated_post
sign_in #user
expect {
post(:up_vote, post_id: #post.id)
}.to change { #post.up_votes }.by 1
end
end
end
votes_controller.rb
class VotesController < ApplicationController
before_action :load_post_and_vote
def up_vote
update_vote!(1)
redirect_to :back
end
def down_vote
update_vote!(-1)
redirect_to :back
end
def update_vote!(new_value)
if #vote
authorize #vote, :update?
#vote.update_attribute(:value, new_value)
else
#vote = current_user.votes.build(value: new_value, post: #post)
authorize #vote, :create?
#vote.save
end
end
private
def load_post_and_vote
#post = Post.find(params[:post_id])
#vote = #post.votes.where(user_id: current_user.id).first
end
end
routes.rb
Rails.application.routes.draw do
devise_for :users
resources :users, only: [:update]
resources :questions
resources :advertisements
resources :topics do
resources :posts, except: [:index] do
resources :summaries, only: [:create, :new, :show]
resources :comments, only: [:create, :destroy]
post '/up-vote', to: 'votes#up_vote', as: :up_vote
post '/down-vote', to: 'votes#down_vote', as: :down_vote
end
end
get 'about' => 'welcome#about'
get 'contact' => 'welcome#contact'
root to: 'welcome#index'
end
Module providing methods within specs:
module TestFactories
def associated_post(options={})
post_options = {
title: 'Post title',
body: 'Post bodies must be pretty long.',
topic: Topic.create(name: 'Topic name'),
user: authenticated_user
}.merge(options)
Post.create(post_options)
end
def authenticated_user(options={})
user_options = {email: "email#{rand}#fake.com", password: 'password'}.merge(options)
user = User.new(user_options)
user.skip_confirmation!
user.save
user
end
end
Relevant Rake Routes
topic_post_up_vote POST /topics/:topic_id/posts/:post_id/up-vote(.:format) votes#up_vote
topic_post_down_vote POST /topics/:topic_id/posts/:post_id/down-vote(.:format) votes#down_vote
Any ideas why I'm getting this URL generation error?
I think you just need to pass the topic_id to the post method like this: post( :up_vote, post_id: #post.id, topic_id: #post.topic.id )
I ended up switching my routes.rb file to the below and got the above vote_controller_spec.rb working.
Rails.application.routes.draw do
devise_for :users
resources :users, only: [:update]
resources :questions
resources :advertisements
resources :topics do
resources :posts, except: [:index]
end
resources :posts, only: [] do
resources :summaries, only: [:create, :new, :show]
resources :comments, only: [:create, :destroy]
post '/up-vote', to: 'votes#up_vote', as: :up_vote
post '/down-vote', to: 'votes#down_vote', as: :down_vote
end
get 'about' => 'welcome#about'
get 'contact' => 'welcome#contact'
root to: 'welcome#index'
end

Resources