Refactor nested routes for common default - ruby-on-rails

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

Certain namespaced routes being ignored

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]

uninitialized constant UsersController

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

How can I alias or rewrite a set of resource routes to another namespace in Rails 4?

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

How to set default format for routing in Rails?

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

Implementing REST-api with different defaults format

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' }

Resources