I have some routes for an API which all have the same defaults (format: :json):
namespace :api do
namespace :v1 do
resources :users, only: [:index, :show, :update], defaults: { format: :json }
resources :items, only: [:index, :show, :update, :destroy], defaults: { format: :json }
resources :posts, only: [:index, :show, :update], defaults: { format: :json }
resources :comments, only: [:index, :show, :update], defaults: { format: :json }
resources :flags, only: [:index, :show, :update, :create], defaults: { format: :json }
end
end
Is there a way to refactor/DRY the code to set the defaults (or even the only) in just one place for only this set of routes? The app also serves HTML at other routes, so it can't be a blanket setting for the whole app.
Move defaults: {format: :json} and the common only options at namespace level. Namespace have them as an option.
namespace :api, defaults: { format: :json }, only: [:index, :show, :update] do
namespace :v1 do
resources :users
resources :items, only: [:index, :show, :update, :destroy]
resources :posts
resources :comments
resources :flags, only: [:index, :show, :update, :create]
end
end
You can use iterator like the following:
[:users, :items, :posts, :comments, :flags].each do |res|
resources res, only:[...], defaults: {}
end
but I see you have different only so you can also pass it to iterator
Related
I have the following routes
resources :eclubs, except: [:show]
namespace :eclubs do
resources :leaders, only: [:index, :show, :new, :create, :destroy]
resources :members, only: [:index, :show, :new, :create, :destroy]
end
However, /eclubs/members does not routes to the index action of the Eclubs::Members controller. Instead it routes to the show action of the Eclubs controller. How do I fix this?
Because it is declared first, the Eclubs controller is being given precedence over the Eclubs::Members. Instead declare the Eclubs controller's routes last e.g.
namespace :eclubs do
resources :leaders, only: [:index, :show, :new, :create, :destroy]
resources :members, only: [:index, :show, :new, :create, :destroy]
end
resources :eclubs, except: [:show]
I am using devise and therefore do not need a users controller.However, i also need nested routes and my config.routes looks like this;
devise_for :admin_users, ActiveAdmin::Devise.config
ActiveAdmin.routes(self)
devise_for :users
resources :users do
resources :personal_accounts,path: "user_account", only: [:show] do
resources :deposits, only: [:new, :show, :create, :index]
resources :withdraws, only: [:new, :show, :create, :index]
end
resources :businesses do
resources :business_accounts, path: "business_account", only: [:show] do
resources :business_withdraws, only: [:new, :show, :create, :index]
resources :business_deposits, only: [:new, :show, :create, :index]
end
end
end
How can i go past this error while also maintaining my nested routes.
Thank you.
You have three levels of nested routes there, which is normally considered to be undesirable: http://edgeguides.rubyonrails.org/routing.html#nested-resources
Resources should never be nested more than 1 level deep.
This bit resources :users do will create all the named routes for the users controller, which I suspect is where your error comes from. Why do you need this? Better perhaps to specify the routes without it?
resources :personal_accounts,path: "user_account", only: [:show] do
resources :deposits, only: [:new, :show, :create, :index]
resources :withdraws, only: [:new, :show, :create, :index]
end
I have a bunch of resources that I want to make available at both /api/[PATH] and /api/v1/[PATH]. In other words, both /api/tasks/12 and /api/v1/tasks/12 should be routed to Api::V1::TasksController#show. However, for reasons of backward-compatibility I don't want to use external redirects - all the routing should happen internally.
This is the best I've found so far, but it requires replicating the resource declarations:
namespace :api, defaults: {format: :json} do
namespace :v1, as: 'v1' do
resource :profile, only: [:show]
resources :notifications, only: [:create]
resources :tasks, only: [:index, :create, :show, :update]
end
scope module: 'v1' do
resource :profile, only: [:show]
resources :notifications, only: [:create]
resources :tasks, only: [:index, :create, :show, :update]
end
end
Yes, I could put them in a Proc if I really wanted to avoid duplication, but that just seems ridiculous.
I tried something like match '*path', path: '/v1', via: :all (inside the first namespace) but that didn't seem to work.
Surely there's a better way of doing this?
Routes
I understand your question - you want the same routes (including controllers) to be defined for the /v1 API as the standard /api.
The best I can give is to help you define some routing concerns:
#config/routes.rb
concern :api do
resource :profile, only: [:show]
resources :notifications, only: [:create]
resources :tasks, only: [:index, :create, :show, :update]
end
namespace :api, defaults: {format: :json} do
scope module: "v1" do
concerns :api
end
namespace :v1, as: 'v1' do
concerns: :api
end
end
I know it's a bit WET, but it's the surest way to achieve what you're looking for
There is the following code for routing:
resources :orders, only: [:create], defaults: { format: 'json' }
resources :users, only: [:create, :update], defaults: { format: 'json' }
resources :delivery_types, only: [:index], defaults: { format: 'json' }
resources :time_corrections, only: [:index], defaults: { format: 'json' }
It is possible to set default format for all resources using 1 string without 'defaults' hash on each line? Thanks.
Try something like this:
scope format: true, defaults: { format: 'json' } do
resources :orders, only: [:create]
resources :users, only: [:create, :update]
resources :delivery_types, only: [:index]
resources :time_corrections, only: [:index]
end
I'd rather add method to application_controller. And use it as before filter where I want.
class ApplicationController < ActionController::Base
...
private
...
def set_default_format
params[:format] ||= "json"
end
end
class UsersController < ApplicationController
before_filter :set_default_format, only: [:create]
...
end
In this case default format wouldn't a surprise for new developers, because usually routes.rb is big and cumbersome
That worked for me:
scope defaults: { format: 'json' } do
resources :users, only: [:index]
end
I have a little REST-controller named password_resets, it has only create, show and update methods.
In routes.rb:
resources :password_resets, :only => [:create, :show, :update]
and I want one of the actions can manipulate with json by default, but others not. For all actions I can do:
scope :defaults => {format: 'json'} do
resources :password_resets, :only => [:create, :show, :update]
end
but how to do the same only for one action?
you can use multiple lines to setup differents formats:
resources :password_resets, :only => [:create, :update]
resources :password_resets, :only => [:show], :defaults => { :format => 'json' }