'Where is the login_url defined? NameError: undefined local variable or method `login_url'

I am reading Agile Development with Rails 5 by Sam Ruby. https://pragprog.com/book/rails51/agile-web-development-with-rails-5-1

In Chapter 14 Task I:Logging in after I use rails test, the console gives the following errors

Error:
ProductTest#test_image_url:
NameError: undefined local variable or method `login_url' for #<ProductTest:0x00000000062aadb8>
Did you mean?  login_as
    test/test_helper.rb:10:in `login_as'
    test/test_helper.rb:16:in `setup'


bin/rails test test/models/product_test.rb:38

E

Error:
ProductTest#test_product_price_must_be_positive:
NameError: undefined local variable or method `login_url' for #<ProductTest:0x0000000005b9b068>
Did you mean?  login_as
    test/test_helper.rb:10:in `login_as'
    test/test_helper.rb:16:in `setup'


bin/rails test test/models/product_test.rb:15

E

Error:
ProductTest#test_product_is_not_valid_without_a_unique_title:
NameError: undefined local variable or method `login_url' for #<ProductTest:0x0000000008349948>
Did you mean?  login_as
    test/test_helper.rb:10:in `login_as'
    test/test_helper.rb:16:in `setup'


bin/rails test test/models/product_test.rb:50

E

Error:
ProductTest#test_product_attributes_must_not_be_empty:
NameError: undefined local variable or method `login_url' for #<ProductTest:0x0000000007ff8c08>
Did you mean?  login_as
    test/test_helper.rb:10:in `login_as'
    test/test_helper.rb:16:in `setup'


bin/rails test test/models/product_test.rb:6

.......E

Error:
UserStoriesTest#test_buying_a_product:
ActionView::Template::Error: undefined method `each' for nil:NilClass
    app/views/store/index.html.erb:7:in `block in _app_views_store_index_html_erb__32180898452112054_53581700'
    app/views/store/index.html.erb:6:in `_app_views_store_index_html_erb__32180898452112054_53581700'
    test/integration/user_stories_test.rb:16:in `block in <class:UserStoriesTest>'

I tried searching for a solution online but could'nt find one. Agile Web Development Rails 5 test failures This is a similar problem with same error but I didn' understand the solution

My test/test_helper.rb


    ENV['RAILS_ENV'] ||= 'test'
    require_relative '../config/environment'
    require 'rails/test_help'

    class ActiveSupport::TestCase
  # Setup all fixtures in test/fixtures/*.yml for all tests in alphabetical order.
  fixtures :all

def login_as(user)
post login_url, params: { name: user.name, password: 'secret' }
end
def logout
delete logout_url
end
def setup
login_as users(:one)
end


  # Add more helper methods to be used by all tests here...
end

My config/routes.rb

Rails.application.routes.draw do
get 'admin' => 'admin#index'

  controller :sessions do
    get  'login' => :new
    post 'login' => :create
    delete 'logout' => :destroy
  end

  resources :users
  resources :orders
  resources :line_items
  resources :carts
  root 'store#index', as: 'store_index'

  resources :products do
    get :who_bought, on: :member
  end

end


Solution 1:[1]

In the tutorial, login_url is intended to be a URL helper defined by Rails, based on this line in routes.rb:

controller :sessions do
  get  'login' => :new
end

All routes have a helper generated to reach them, and you can grep this using rails routes -G login. In your case, this will give a line something like:

login GET   /login(.:format)     sessions#new

What this shows is 1) the route name and HTML method, 2) the path and 3) the controller#action handling it.

In the above example, login_url would work, as the route name can be suffixed by either _url or _path due to the auto-generated helper.

However, it's likely you won't see exactly this as you're having problems. You might see, for example:

sessions GET   /login(.:format)     sessions#new

This means you have two options:

Use sessions_url in place of login_url.

Or, and likely the correct solution, name your route in routes.rb using as:

controller :sessions do
  get  'login' => :new, as: 'login'
end

Do that, and your route should be renamed to login and therefore login_url be made available.

Let me know how you get on or if you've any questions :)

Solution 2:[2]

@rohitjoshi Please declare the ActionDispatch class, as follows:

ENV['RAILS_ENV'] ||= 'test'
require_relative '../config/environment'
require 'rails/test_help'

class ActiveSupport::TestCase
  # Run tests in parallel with specified workers
  parallelize(workers: :number_of_processors)

  # Setup all fixtures in test/fixtures/*.yml for all tests in alphabetical order.
  fixtures :all

  # Add more helper methods to be used by all tests here...
end

class ActionDispatch::IntegrationTest
  def login_as(user)
    post login_url, params: { name: user.name, password: 'secret' }
  end

  def logout
    delete logout_url
  end

  def setup
    login_as users(:one)
  end
end

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 SRack
Solution 2 Colin He