Nested resource: controller spec doesn't call the wanted action - ruby-on-rails

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

Related

params on my controllers is missing or the value is empty

I have a test in rspec that is not passing and I do not know the reason. The test accuses the following:
1) SalesmenController POST #create redirect to new team
Failure/Error: params.require(:salesmen).permit(:name, :company_id)
ActionController::ParameterMissing:
param is missing or the value is empty: salesmen
The test is:
require 'rails_helper'
RSpec.describe SalesmenController, type: :controller do
include Devise::Test::ControllerHelpers
before(:each) do
#request.env["devise.mapping"] = Devise.mappings[:owner]
#current_owner = FactoryGirl.create(:owner)
sign_in #current_owner
#current_company = FactoryGirl.create(:company, owner: #current_owner)
end
describe "POST #create" do
before(:each) do
salesman = create(:salesman, company: #current_company)
post :create, params: {:company_id => #current_company.id, company: { name: salesman.name, company_id: #current_company.id } }
end
it "redirect to new team" do
expect(response).to have_http_status(:success)
end
it "Create team with right attributes" do
expect(Salesman.last.company).to eql(#current_company)
expect(Salesman.last.name).to eql(#salesman[:name])
end
end
end
My controller is:
def create
#salesman = Salesman.new(params_salesman)
authorize! :create, #salesman
if #salesman.save
redirect_to company_salesman_path
flash[:notice] = "Salesman saved!"
else
flash.now[:error] = "Could not create salesman!"
render :new
end
end
private
def params_salesman
params.require(:salesman).permit(:name, :company_id)
end
My routes are:
Rails.application.routes.draw do
resources :companies do
resources :salesmen
resources :goals do
resources :days
end
end
devise_for :owners, :controllers => { registrations: 'registrations' }
end
My factory is:
FactoryGirl.define do
factory :salesman do
name {FFaker::Name.name}
company
end
end
Anyone know what could be happening?
Try params.permit(:name, :company_id) instead of params.require(:salesman).permit(:name, :company_id). Reason being that in your test environment, you don't have salesman coming in your params.

Devise unable to get current_user

I want to get the token of the successfully logged user so I created the get_token method in my Application Controller:
def after_sign_in_path_for(resource)
if current_user.role.role_type === 'user'
current_user.regenerate_token
#user_token = current_user.token
puts #user_token #logging properly
user_profile_path
else
rails_admin_path
end
end
def get_token
return #user_token
end
Now, I want to get the value of the token in my controller namely, Api::V1::CommentController so i have my code
class Api::V1::CommentController < ApplicationController
def initialize
#http_status = { :status => false }
end
def create
puts get_token #I just want to log this
render :json => #http_response
end
end
With the code above, I am not getting the generated token when testing it using POSTMAN. What am I doing wrong?
EDIT:
I have this in my routes:
namespace :api do
namespace :v1 do
devise_scope :user do
post 'comment/create' => 'comment#create'
end
end
end
The instance variable you are setting will be available for only that specific request.
Just change the method to
def get_token
current_user.token
end

Rspec: why is my post :create throwing a :new route not found error?

In a little Rspec test like this:
describe 'POST create' do
context 'with valid attributes' do
#document = FactoryGirl.attributes_for(:document_with_publication)
it 'creates a new document' do
sign_in admin
post :create, document: #document
expect(response).to change(Document, :count).by(1)
end
end
end
I get this error:
DocumentsController user is an administrator POST create with valid attributes creates a new document
Failure/Error: post :create, document: #document
ActionController::RoutingError:
No route matches {:controller=>"documents", :action=>"new", :template=>nil}
Why do I seem to be hitting my :new action and not :create? My routes look like this:
resources :documents, except: [:new, :show]
get 'documents/:template/new', to: 'documents#new', as: :new_templated_document
Thanks. Relevant controller code is here:
def new
#document = current_user.documents.new
#document.template = Template.find(params[:template])
#template_resources = TemplateResources.new(#document, current_user)
end
def create
#document = current_user.documents.new(params[:document])
if #document.save
second_stage_processing
else
redirect_to new_templated_document_path(#document.template), flash:
{ error: 'The document you tried to create was invalid: ' \
"#{#document.errors.full_messages.map { |msg| msg }.join}" }
end
end
I think it is hitting the create action and the #document.save is failing which causes the redirect to redirect_to new_templated_document_path(#document.template) to be called. Since :template is required for that route, but is nil, the route is failing.

How to nest collection routes?

I use the following routes configuration in a Rails 3 application.
# config/routes.rb
MyApp::Application.routes.draw do
resources :products do
get 'statistics', on: :collection, controller: "statistics", action: "index"
end
end
The StatisticController has two simple methods:
# app/controllers/statistics_controller.rb
class StatisticsController < ApplicationController
def index
#statistics = Statistic.chronologic
render json: #statistics
end
def latest
#statistic = Statistic.latest
render json: #statistic
end
end
This generates the URL /products/statistics which is successfully handled by the StatisticsController.
How can I define a route which leads to the following URL: /products/statistics/latest?
Optional: I tried to put the working definition into a concern but it fails with the error message:
undefined method 'concern' for #<ActionDispatch::Routing::Mapper ...
I think you can do it by two ways.
method 1:
resources :products do
get 'statistics', on: :collection, controller: "statistics", action: "index"
get 'statistics/latest', on: :collection, controller: "statistics", action: "latest"
end
method 2, if you have many routes in products, you should use it for better organized routes:
# config/routes.rb
MyApp::Application.routes.draw do
namespace :products do
resources 'statistics', only: ['index'] do
collection do
get 'latest'
end
end
end
end
and put your StatisticsController in a namespace:
# app/controllers/products/statistics_controller.rb
class Products::StatisticsController < ApplicationController
def index
#statistics = Statistic.chronologic
render json: #statistics
end
def latest
#statistic = Statistic.latest
render json: #statistic
end
end

NoMethodError in controller#new - undefined method

I'm getting a NoMethodError in the new action of my business_controller.
It seems to be acessing the #business object for a form in my view and the error occurs then:
undefined method `businesses_path' for
Here is my new method:
def new
if Business.where(:user_id => current_user.id).first.blank?
#business = Business.new
else
redirect_to user_businesses_path(current_user.id)
end
end
My routes are:
resources :users do
resources :businesses
member do
get 'account'
post 'payment'
put 'update_password'
get 'membership'
end
end
mind.blank's suggested changes
before_filter :check_if_user_has_business, :only => :index
def new
#business = Business.new
end
private
def check_if_user_has_business
redirect_to new_user_business_path(current_user) unless current_user.business
end
Do you have a route businesses_path or only user_businesses_path? If you only have the second one then you should specify that URL in your form:
<%= form_for #business, url: user_businesses_path do |f| %>
Also, if you have the correct associations set up, then you can write your if statement as follows:
if current_user.business.nil? # since it's a has_one association
Here's how I would write it:
Class BusinessesController < ApplicationController
before_filter :check_if_user_has_business, only: :new
def new
#business = Business.new
end
private
def check_if_user_has_business
redirect_to user_businesses_path(current_user) if current_user.business
end
end

Resources