5
votes

I have my API in a versioned namespace,

namespace :api do
  namespace :v1 do
    resources :posts
  end
end

but now when I have my controller do a redirect_to @post I get a route error for Post because no routes are defined for it.

def create
  @post = Post.new(params[:post])
  if @post.save
    redirect_to @post
  else
    # ...
  end
end

undefined method `post_url' for #<Api::V1::PostsController:0x007fb9c5fc8858>

I know I can update my controller to redirect to the named route and its not the end of the world:

def create
  @post = Post.new(params[:post])
  if @post.save
    redirect_to api_v1_post_url(@post)
    # or redirect_to [:api, :v1, @post]
  else
    # ...
  end
end

Is there a way to make redirect_to @post automatically detect that it should be in the right api version (so rails works out to use api_v1_post_url)? I know I could overwrite redirect_to but really I want a namespace aware url_for, maybe rails provides some hooks for this?

1

1 Answers

11
votes

There are three options in Ruby on Rails router

1. Namespaces(something which are you using right now)

namespace :api do
  namespace :v1 do
    resources :posts
  end
end

Controller: app/controllers/api/v1/PostsController.rb

Example URL Path: example.com/api/v1/posts


2. Scope(only sets the url path)

scope 'api/v1' do
 resources :posts
end

Controller: app/controllers/PostsController.rb

Example URL Path: example.com/api/v1/posts


3. Module(only sets the controller)

 scope module: 'api/v1' do
   resources :posts
 end

Controller: app/controllers/api/v1/PostsController.rb

Example URL Path: example.com/posts


As you may notice from above, all of three do something similar to what you want but not the way you want it.

the only workaround I can think of against using awkwardly long path helpers api_v1_post_url is to use named routes to shorten it.

namespace :api, :as => "a" do
  namespace :v1, :as => "1" do
    resources :posts
  end
end

so instead of api_v1_post_url

def create
  @post = Post.new(params[:post])
  if @post.save
    redirect_to api_v1_post_url(@post)
  end
end

you can use little shorter a_1_post_url

def create
  @post = Post.new(params[:post])
  if @post.save
    redirect_to a_1_post_url(@post)
  end
end

Lastly, I am afraid, I am not aware of any way to intelligently auto-detect namespacing in rails routing.

Hope it helps