Using Rails 3.0.7, I'm creating an API for our app, and I have this setup:
routes.rb
namespace :api do
namespace :v1 do
match "connect" => "users#login", :via => :post
match "disconnect" => "users#logout", :via => :post
resources :users
match "users/:id/foos" => "foos#list", :via => :get
match "users/:id" => "users#update", :via => :put
match "foos/:id/bars" => "bars#list_by_foo", :via => :get
match "foos/:id" => "foos#show", :via => :get, :constraints => { :id => /\d+/ }
match "bars/:id" => "bars#show", :via => :get
end
end
# other routes here e.g.
match "users/find" => "users#find_by_name", :via => :get
match "users" => "users#create", :via => :post
And then I have my regular app/controllers/application_controller.rb
and app/controllers/users_controller.rb
files as well as my app/controllers/api/v1/application_controller.rb
and app/controllers/api/v1/users_controller.rb
files that are defined like the following:
class Api::V1::ApplicationController < ApplicationController
before_filter :verify_access
def verify_access
# some code here
end
end
class Api::V1::UsersController < Api::V1::ApplicationController
skip_before_filter, :except => [:show, :update, :delete]
end
And before everything seemed to be working right until I overrode a method that is shared by both UsersController and Api::V1::UsersController -- and now it seems like everything is pointing to UsersController even though I'm accessing through the api/v1/users route.
I'm at my wit's end trying to figure it out. Any suggestions? Thanks. PS - feel free to comment with whatever conventions I'm ignoring that I shouldn't be or other things I might have messed up :)
skip_before_filter
also general takes a symbol parameter for the before filter than you wish to skip. Controller names should not have to be unique as long as the proper scoping/namespacing is applied.
example
- api/users_controller
- admin/users_controller
- users_controller
then the code per controller
class Api::V1::UsersController < Api::V1::BaseController
end
class Admin:UsersController < Admin::BaseController
end
class UsersController < ApplicationController
end
Then the routes
MyApp::Application.routes.draw do
scope :module => "api" do
namespace :v1 do
resources :users
end
end
namespace :admin do
resources :users
end
resources :users
end
Rails is a bit confusing, but I had a similar problem. Here's some steps you can take to make sure you're not missing any small code issues. (this eventually led me to discover a syntax bug in the namespaced controller).
- run
bundle exec rake routes
to generate a list of what route links to what controller and action. If this is good, then move to step 2. If not, fix your routes file and try again. (many good tutorials on this, so I won't go into detail)
Go into the rails console, and just load the controller class. If it doesn't work, you may have discovered a bug in syntax. Here's what happened on console when I tried to load the Api::V2::CampaignsController
.
irb> Api::V2::CampaignsController
=> CampaignsController
Note: Rails is directing all requests to the wrong controller (based on Rails' fancy logic to load controller classes). It should goto Api::V2::CampaignsController, but instead it is loading CampaignsController.
You can also verify it in the console with:
> app.get '/api/v2/campaigns.json'
> app.controller.class
=> CampaignsController
# This is not the expected controller.
This ended up being a syntax problem in a class I was extending from the Api::V2::CampaignsController.
It was a bit mind-boggling, but hope this helps someone else.