My routes file looks like this:
resources :people do
resources :text_messages, only: [:index, :new, :create]
end
And my /app/controllers/text_messages_controllers.rb looks like:
class TextMessagesController < ApplicationController
def index
puts 'You have reached the index controller'
#messages = Message.all
end
end
Here's the /spec/controllers/text_messages_controller_spec.rb
describe TextMessagesController do
describe 'GET #index' do
it 'shows all the messages to that user' do
person = create(:person)
message = create(:message, person: person)
get :index, person_id: person.id
expect(assigns(:messages)).to include(message)
end
end
end
When I run the test however, it fails saying #messages is nil and does not print out the text. Why is this test not reaching the controller action? It works great in development when I visit the url.
Related
I have a ReportsController, nested in ProjectsController, with a #show method:
def show
# Some stuff
do_something(#report)
end
Routes:
resources :projects do
resources :reports
end
I need to test that the do_something method is called:
it 'calls do_something' do
expect(controller).to receive(:do_something)
project = create :project
report = create :report, project: project
get :show, params: {project_id: project.id, id: report.id}
end
I placed binding.pry within the #show action, but this doesn't get called. So what's wrong with my spec?
The problem was that I wasn't logged in:
before do
#user = create :user, :admin
sign_in_as #user
end
I have a user profile controller called "userinfo" and it's corresponding view. The userinfo index is the root path. In the homepage(which is the userinfo index), I have a link that takes you to the user profile page. It is giving me this error when I go to the home page:
My routes are:
My userinfos_controller:
class UserinfosController < ApplicationController
before_action :find_userinfo, only: [:show, :edit, :update, :destroy]
before_action :authenticate_user!
def index
#userinfors = Userinfo.find(params[:id])
end
def show
#myvideo = Video.last
end
def new
#userinformation = current_user.userinfos.build
end
def create
#userinformation = current_user.userinfos.build(userinfo_params)
if #userinformation.save
redirect_to root_path
else
render 'new'
end
end
def edit
end
def update
end
def destroy
#userinformation.destroy
redirect_to userinfo_path
end
private
def userinfo_params
params.require(:userinfo).permit(:name, :email, :college, :gpa, :major)
end
def find_userinfo
#userinformation = Userinfo.find(params[:id])
end
end
and my view is:
<%= link_to 'profile', userinfors_path(#userinfors) %>
My routes.rb file:
Rails.application.routes.draw do
devise_for :users
resources :userinfos do
resources :videos
end
resources :pages
get '/application/decide' => 'application#decide'
root 'userinfos#index'
get '/userinfos/:id', to: 'userinfos#show', as: 'userinfors'
end
Thanks for any help!
ok, there are multiple errors and you are not following conventions of rails, index is not for what you have used.
Index is used to list all the users and show for a particular one with id passed in params.
Your index path is, as you can see, /userinfos which is correct and it doesn't have any id with it but you are trying to find user with params[:id] which is nil and hence the error.
Lets try out this:
def index
#userinfors = Userinfo.all #pagination is recommended
end
In your index view,
<% #userinfors.each do |userinfor| %>
<%= link_to "#{userinfor.name}'s profile", userinfo_path(userinfor) %>
<% end %>
It should work now.
Please read routing and action controller to get the idea and understand the magic behind rails routing and mvc architecture..
I'm working on a group project building a chess application & trying to understand why I am getting a routing error when running this test.
I am trying to test the update action in my pieces controller, to make sure that it redirects once a piece is moved. Bare in mind I am new to testing and am guessing that there is a problem with how I've written this one. Really stuck and could use an explanation of what I am missing.
controller:
class PiecesController < ApplicationController
before_action :authenticate_user!, only: [:show, :update]
def show
#show the board again
#game = Game.find(params[:id])
#pieces = #game.pieces
end
def update
#piece = Piece.find(params[:id])
#game = #piece.game
if #piece.update_attributes(piece_params)
redirect_to game_path(#game)
end
end
private
def piece_params
params.require(:piece).permit(:x_position, :y_position)
end
end
spec:
require 'rails_helper'
RSpec.describe PiecesController, type: :controller do
describe 'update action' do
it 'should redirect to game path when piece is moved' do
user1 = FactoryGirl.create(:user)
game = FactoryGirl.create(:game, white_user_id: user1.id )
piece = FactoryGirl.create(:piece, game: game, user_id: user1.id, x_position: 0, y_position: 0)
put :update, params: {x_position: 1, y_position: 1}
expect(response).to redirect_to game_path(game)
end
end
end
routes:
Rails.application.routes.draw do
devise_for :users
root 'static_pages#index'
resources :games do
member do
patch :join
end
resources :pieces, only: [:show, :update]
end
end
You're missing id on put :update, params: {x_position: 1, y_position: 1}?
You probably want something like:
put :update, id: piece.id, game_id: game.id, piece: {x_position: 1, y_position: 1}
I am writing a rails application with devise and testing in rspec. I have an issue where my rspec fails the user_authenticate when the user is not logged in. All of my specs pass except for the last one- the error it gives is
"Failure/Error: get :show, id: course NoMethodError:undefined method `authenticate' for nil:NilClass"
I suspect I am having this issue because I have a before_action :authenticate_user! call and for someone not logged in, it tries to authenticate nil. Is there a way to make it fail gracefully and redirect to user_session? I tried to create an inherited version of authenticate_user to do the redirect, but it does not appear to work. I know this is probably a noob question but I have extensively searched around without any solution. thanks!
This is my controller:
class CoursesController < ApplicationController
before_action :authenticate_user!, except: [:index]
before_action :set_course, only: [:show]
def index
#course = Course.order('name')
end
def show
end
private
def set_course
#course = Course.find(params[:id])
end
def course_params
params.require(:course).permit(:name,:description,:department,:hidden,
:lecture_attributes => [:name,:description,:level])
end
def authenticate_user!
if user_signed_in?
super
else
redirect_to user_session
end
end
end
This is my spec:
require 'rails_helper'
RSpec.describe CoursesController, :type => :controller do
describe "user access " do
before(:each) do
#user = create(:user)
#request.env['devise.mapping'] = Devise.mappings[:user]
sign_in :user, #user
end
describe 'GET #index' do
it 'renders the :index view' do
get :index
expect(response).to render_template :index
end
end
describe 'GET #show' do
it 'assigns the requested course to #course' do
course = create(:course)
get :show, id: course
expect(assigns(:course)).to eq course
end
it 'renders the :show template' do
course = create(:course)
get :show, id: course
expect(response).to render_template :show
end
end
end
describe "guest access " do
describe 'GET #index' do
it 'renders the :index view' do
get :index
expect(response).to render_template :index
end
end
describe 'GET #show' do
it 'redirects to the login url' do
course = create(:course)
get :show, id: course
expect(response).to redirect_to 'user_session'
end
end
end
end
It seems that devise does the redirect to "users#sessions" itself when you add :authenticate_user! to the show action for a guest or a user that is not signed in.
Try removing your custom :authenticate_user! method and add "only: [:show]" to your before_action
class CoursesController < ApplicationController
before_action :authenticate_user!, only: [:show], except: [:index]
before_action :set_course, only: [:show]
def index
#course = Course.order('name')
end
def show
end
private
def set_course
#course = Course.find(params[:id])
end
def course_params
params.require(:course).permit(:name,:description,:department,:hidden,
:lecture_attributes => [:name,:description,:level])
end
end
Update
class CoursesController < ApplicationController
before_action :authenticate_user!, except: [:index]
before_action :set_course, only: [:show]
def index
#course = Course.order('name')
end
def show
if user_signed_in?
render :show
else
redirect_to user_session
end
end
private
def set_course
#course = Course.find(params[:id])
end
def course_params
params.require(:course).permit(:name,:description,:department,:hidden,
:lecture_attributes => [:name,:description,:level])
end
end
This isn't a super satisfying result but it appears as if authenticate_user! does not properly work with rspec. When I load the page directly, it correctly redirects to the login page, I am still interested to know what the proper work around is.
Can I have some sort of OR statement where I can first check if a user exists? There must be a standard way to deal with this problem so I can ensure my app is properly redirecting.
On RSpec, the destroy action fails in ActionController::InvalidAuthenticityToken.
I don't think this is a problem as skip_before_filter :verify_authenticity_token, :only => [:index, :show] in my Controller is enough to fix the problem, but it still bothers me that this has to happen and it seems like it could be a bad security practice.
-
Here's the would-be-failing RSpec test:
require 'spec_helper'
describe "Products" do
subject { page }
...
describe "Destroy" do
before {
FactoryGirl.create(:product)
visit products_path
}
it "should have a destroy link" do
expect { should have_link('Destroy') }
end
it "link should destroy" do
expect do
click_link('Destroy', match: :first)
end.to change(Product, :count).by(-1)
end
end
end
-
And here's the controller:
class ProductsController < ApplicationController
before_action :set_product, only: [:show, :edit, :update, :destroy]
skip_before_filter :verify_authenticity_token, :only => [:destroy] #destroy wasn't working without this
def index
#products = Product.all
end
def show
end
def new
#product = Product.new
end
def edit
end
def create
...
end
def update
...
end
def destroy
#product.destroy
flash[:notice] = "Product was successfully destroyed."
redirect_to products_path
end
private
# Use callbacks to share common setup or constraints between actions.
def set_product
#product = Product.find(params[:id])
end
# Never trust parameters from the scary internet, only allow the white list through.
def product_params
params.require(:product).permit(:title, :description, :image_url, :price)
end
end
-
Ideas?
You are correct, skipping your authenticity token check is a bad idea. At the very least, ensure you are only doing that for your test environment:
skip_before_filter :verify_authenticity_token, :only => [:destroy] if Rails.env.test?
The issue with invalid tokens when you run tests may be the result of running your tests in your development environment.
Ensure your test_helper.rb file is correctly setting the environment:
Rails.env = 'test'
This works better than the ENV['RAILS_ENV'] = 'test' style approach.
Best of luck! Did you happen to find any other resolution?