I have the following routes:
config/routes.rb:
Rails.application.routes.draw do
scope module: :api do
namespace :v1 do
resources :users
end
end
end
controllers/api/v1/users_controller.rb:
module Api
module V1
class UsersController < ApplicationController
def index
...
end
end
end
end
The controller specs are under the folder spec/controllers/api/v1/.
spec/controllers/api/v1/users_controller_spec.rb:
module Api
module V1
RSpec.describe UsersController, type: :controller do
let!(:users) { create_list(:user, 10) }
describe 'GET /v1/users' do
before { get :index }
# Already tried `get '/v1/users'`, got the same error
it 'should return 10 users' do
expect(JSON.parse(response).size).to eq(10)
end
end
end
end
end
Once I run the tests I receive the following error:
ActionController::UrlGenerationError:
No route matches {:action=>"index", :controller=>"api/v1/users"}
Note that it "infers" the api part from somewhere, but my routes are like these:
v1/users
v1/users/:id
...
How can I make it work?
I believe this is because you are namespacing your test with Api::V1::UsersController, but your route is defined within the scope of Api. That's why your routes are not under /api
Try removing the Api module from the controller and test or changing scope module: :api to namespace :api
Alternatively, you could keep it all as-is and make the get request to your v1_users_path or whatever the corresponding path is when you run rails routes (instead of :index).
Related
I'm really struggling how to setup controller which are placed in subfolder? I already tried below but I got an error in my console. Somebody helped how to achieve and fix this, I'm from laravel and I using rails now.
Error in my console:
'Api/Auth/register' is not a supported controller name. This can lead to potential routing problems.
My target route is this below:
http://localhost:3000/api/auth/register
Below image is directory where I place the register_controller
Here's inside of my routes.rb
Rails.application.routes.draw do
namespace 'Api' do
namespace 'Auth' do
get 'register', to: 'register#store'
end
end
end
And in my register_controller.rb is below:
module Api
module Auth
class RegisterController < ApplicationController
def store
render json: { code: 200, data: 'sample' }, status: :ok
end
end
end
end
You need to setup a namespace for your controller, and then a route for each of your actions (methods in your controllers). Also, the namespace is usually lower case.
Rails.application.routes.draw do
namespace 'api' do
namespace 'auth' do
namespace 'register' do
get 'store'
end
end
end
end
I'm trying to write a controller specs for one of my controller action defined under Front namespace (and living in Front engine mounted in root rails app). I've been following this thing to acheive that: https://www.relishapp.com/rspec/rspec-rails/docs/controller-specs/engine-routes-for-controllers
Here is my code:
# config/routes/rb
Rails.application.routes.draw do
mount Front::Engine => '/', as: 'front'
end
# modules/front/config/routes.rb
Front::Engine.routes.draw do
resources :items
end
# modules/front/app/controllers/front/items_controller.rb
class Front::ItemsController < Front::ApplicationController
def index
# ...
end
end
# spec/controllers/front/items_controller_spec.rb
require 'rails_helper'
RSpec.describe Front::ItemsController, type: :controller do
routes { Front::Engine.routes }
describe "GET index" do
it "assings #items" do
item = FactoryGirl.create(:item)
get :index
expect(assigns(:items)).to eq([item])
end
end
end
Running above spec gives me:
Front::ItemsController
GET index
assings #items (FAILED - 1)
Failures:
1) Front::ItemsController GET index assings #items
Failure/Error: get :index
ActionController::UrlGenerationError:
No route matches {:action=>"index", :controller=>"front/items"}
It all works fine outside of specs, i can totally access that endpoint. Any ideas what's wrong in here? Thanks in advance.
ruby 2.3.1
rspec 3.4.4
rails 4.2.1
Rspec fails with ActionController::UrlGenerationError with a URL I would think is valid. I've tried messing with the params of Rspec request, as well as fiddled with the routes.rb, but I'm still missing something.
The weird thing is, it works 100% as expected when testing locally with curl.
Error:
Failure/Error: get :index, {username: #user.username}
ActionController::UrlGenerationError:
No route matches {:action=>"index", :controller=>"api/v1/users/devices", :username=>"isac_mayer"}
Relevant code:
spec/api/v1/users/devices_controller_spec.rb
require 'rails_helper'
RSpec.describe Api::V1::Users::DevicesController, type: :controller do
before do
#user = FactoryGirl::create :user
#device = FactoryGirl::create :device
#user.devices << #device
#user.save!
end
describe "GET" do
it "should GET a list of devices of a specific user" do
get :index, {username: #user.username} # <= Fails here, regardless of params. (Using FriendlyId by the way)
# expect..
end
end
end
app/controllers/api/v1/users/devices_controller.rb
class Api::V1::Users::DevicesController < Api::ApiController
respond_to :json
before_action :authenticate, :check_user_approved_developer
def index
respond_with #user.devices.select(:id, :name)
end
end
config/routes.rb
namespace :api, path: '', constraints: {subdomain: 'api'}, defaults: {format: 'json'} do
namespace :v1 do
resources :checkins, only: [:create]
resources :users do
resources :approvals, only: [:create], module: :users
resources :devices, only: [:index, :show], module: :users
end
end
end
Relevant line from rake routes
api_v1_user_devices GET /v1/users/:user_id/devices(.:format) api/v1/users/devices#index {:format=>"json", :subdomain=>"api"}
The index action requires a :user_id parameter, but you haven't supplied one in the params hash. Try:
get :index, user_id: #user.id
The error message is a bit confusing, because you aren't actually supplying a URL; instead you are calling the #get method on the test controller, and passing it a list of arguments, the first one is the action (:index), and the second is the params hash.
Controller specs are unit tests for controller actions, and they expect that the request parameters are correctly specified. Routing is not the responsibility of the controller; if you want to verify that a particular URL is routed to the right controller action (since as you mention, you are using friendly-id), you may want to consider a routing spec.
Attempting to create an API using doorkeeper. When I sign into my account and the session user is authenticated and access my API on
http://localhost:3000/api/v1/trials
I get a routing error page saying "uninitialized constant TrialsController" and a rake routes listing. Including:
trials_path GET /api/v1/trials(.:format) trials#index
I am using rails version 4.0.3, ruby 2.0.0. This is my config/routes.rb file:
MyApp::Application.routes.draw do
devise_for :users
use_doorkeeper :scope => 'oauth2' do
end
root :to => 'welcome#index'
scope 'api' do
scope 'v1' do
resources :trials
end
end
end
My app/ dir contains:
app/
controllers/
application_controller.rb
welcome_controller.rb
api/
v1/
trials_controller.rb
My trials_controller.rb is:
module Api::V1
class TrialsController < ::ApplicationController
doorkeeper_for :all
def index
#trials = Trials.all
end
def show
...
end
...
end
end
UPDATE:
When I change the routes.rb to namespace the trails controller like so:
namespace :api do
namespace :v1 do
resources :trails
end
end
I get a "no route matches" error when attempting to access:
http://localhost:3000/api/v1/trials(.json)
(With or without the extension.)
I have also added to trials#index:
def index
#trials = Trials.all
respond_to do |format|
format.json { render :json => #trials }
format.xml { render :xml => #trials }
end
end
Also with no luck.
I'm not sure how it would play out against doorkeeper but I have a similar API structure in an app. I have the following in my routes (matching what Sergio notes)
namespace :api, defaults: {format: 'json'} do
namespace :v1 do
resources :api_controller_1
resources :api_controller_2
end
end
And here's how I build my API classes:
module Api
module V1
class ApiNamedController < ApplicationController
# code
end
end
end
I'm trying to test a controller that is inside an engine my application is using. The spec is not within the engine, but in the application itself (I tried to test within the engine but also had problems).
My engine has the following routes.rb:
Revision::Engine.routes.draw do
resources :steps, only: [] do
collection { get :first }
end
end
The engine is mounted on the application routes.rb normally:
mount Revision::Engine => "revision"
When I run rake routes, at the last lines I get:
Routes for Revision::Engine:
first_steps GET /steps/first(.:format) revision/steps#first
root / revision/steps#first
On my engine's controller (lib/revision/app/controllers/revision/steps_controller.rb), I have:
module Revision
class StepsController < ApplicationController
def first
end
end
end
On Rspec, I test this controller with:
require 'spec_helper'
describe Revision::StepsController do
it "should work" do
get :first
response.should be_success
end
end
Then when I run this spec, I get:
ActionController::RoutingError:
No route matches {:controller=>"revision/steps", :action=>"first"}
To be sure that the route doesn't really exist, I added this to the spec:
before do
puts #routes.set.to_a.map(&:defaults)
end
And the result is this:
[...]
{:action=>"show", :controller=>"devise/unlocks"}
{:action=>"revision"}
It has only the :action parameter.
What may be wrong?
When you're trying to test an engine's controllers, you need to specify what route set you want the controller test to use, otherwise it will run it against the main app's. To do that, pass use_route: :engine_name to the get method.
require 'spec_helper'
describe Revision::StepsController do
it "should work" do
get :first, use_route: :revision # <- this is how you do it
response.should be_success
end
end