Rails - route index to first module's object - ruby-on-rails

Say I have a module name Server that was created with a scaffold. I want the url 'www.example.com/server/' to be redirected to the first Server object that exists. So for example to be redirected to 'www.example.com/server/2'.
How could this be done with routes.rb (or any other way)?
route.rb:
Rails.application.routes.draw do
resources :servers
end
Server controller:
class ServersController < ApplicationController
before_action :set_server, only: [:show, :edit, :update, :destroy]
# GET /servers
# GET /servers.json
def index
#servers = Server.all
end
....

your can put
redirect_to server_path(Server.first) and return
inside your index method it'll redirect you when ever index action is called.
and just to extent #richfisher's answer (which might be a more appropriate way to do it.)
resources :servers, except: [:index] # this won't generate redundant routes
get '/servers/' => 'servers#first' #note this is now accessible via "server_path" instead of "servers_path" helper.

For what it's worth, I'd do this:
#config/routes.rb
resources :servers, except: :index do
get "", action: :show, id: Server.first.id, on: :collection
end
This will allow you to use the show action in place of index in a super efficient setup:
#app/controllers/servers_controller.rb
class ServersController < ApplicationController
def show
#server = Server.find params[:id]
end
end

Related

Rails routing to nested controller

I have one controller for creating category, and I want to have one more nested controller to create language versions of categories. I want to avoid methods like new_language, edit_language, ... and routing on them, I would like to do it the best rails way. But I am new to rails (from Padrino and Sinatra), and I am little bit lost in routing.
I have my controller for categories
module Admin
class CategoriesController < ApplicationController
before_action :authenticate_user!
before_action :find_category, only: [:show, :edit, :update]
layout 'admin'
def index
#categories = Category.all
end
..... all the others CRUD methods ....
end
end
And another controller.
module Admin
class CategoriesLanguageController < ApplicationController
before_action :authenticate_user!
before_action :find_category, only: [:show, :edit, :update]
def new
#category = Category.find(params[:category].to_i)
end
.... all the others CRUD methods ...
end
end
and my routes config.
Rails.application.routes.draw do
devise_for :users
resources :users
namespace :admin do
get '/' => 'dashboard#index'
resources :dashboard, only: [:index]
resources :categories do
collection do
get :publish_category
#get :new_lang
#post :create_lang
#get :edit
#post :update
#get :destroy
end
resources :language, only: [:new, :create, :edit]
end
end
# For details on the DSL available within this file, see https://guides.rubyonrails.org/routing.html
root to: "homepage#index"
namespace :api, defaults: { format: 'json' } do
namespace :v1 do
resources :categories, only: [:index]
end
end
end
I would like to have methods new_lang and create_lang under second controller with default names new, create, ....
It generates this
admin GET /admin(.:format) admin/dashboard#index
admin_dashboard_index GET /admin/dashboard(.:format) admin/dashboard#index
publish_category_admin_categories GET /admin/categories/publish_category(.:format) admin/categories#publish_category
admin_category_language_index POST /admin/categories/:category_id/language(.:format) admin/language#create
new_admin_category_language GET /admin/categories/:category_id/language/new(.:format) admin/language#new
edit_admin_category_language GET /admin/categories/:category_id/language/:id/edit(.:format) admin/language#edit
admin_categories GET /admin/categories(.:format) admin/categories#index
POST /admin/categories(.:format) admin/categories#create
new_admin_category GET /admin/categories/new(.:format) admin/categories#new
edit_admin_category GET /admin/categories/:id/edit(.:format) admin/categories#edit
admin_category GET /admin/categories/:id(.:format) admin/categories#show
PATCH /admin/categories/:id(.:format) admin/categories#update
PUT /admin/categories/:id(.:format) admin/categories#update
DELETE /admin/categories/:id(.:format) admin/categories#destroy
but it is not working.
ActionController::UrlGenerationError in Admin::Categories#index
and error is this route:
<td><%= link_to cat.internal_name, edit_admin_category_language_path(id: cat) %></td>
And I don't know how to create these actions in another controller and use url helpers.
Or this is not the best way to do it?
Please any advice?

Route with a query string is passed to incorrect controller action

With my rails api. At the moment if I do a get request to /seasons/2 I correctly have a json returned with the season table item of id= 2 through the Seasons controller show action.
But when I hit a get request to /seasons?id=2 a json is returned with all the season resources with the controller Index Action being hit, instead of the show action.
Below is my routes:
Rails.application.routes.draw do
root to: 'application#not_found'
resources :seasons do
end
end
Seasons controller:
class SeasonsController < ApplicationController
before_action :set_season, only: [:show]
def index
#seasons = Season.all
json_response(#seasons)
end
def show
json_response(#season)
end
private
def set_season
#season = Season.find(params[:id])
end
end
My belief was that rails routing should assign both /seasons/2 and /seasons?id=2 to the show controller action by default
try with this:
// routes.rb
....
resources :seasons, only: [:index, :show]
...
After, check your routes on your terminal with the following command:
rails routes

Two routes for the same action Rails

I have an application that lists all the subaccounts under a main account. However when I click the subaccount, instead of going to do accounts/1/subaccounts/1 I want it to go to subaccounts/1. When I use the for_each statement I get the following error. How can I click on a nested route and have it go to just subaccounts/1 instead of accounts/1/subaccounts/1?
<% #subaccounts.each do |sa| %>
<%= link_to "#{sa.name}", subaccount_path(sa) %>
<% end %>
Routes.rb
resources :subaccounts
resources :accounts do
resources :subaccounts
end
Subaccounts controller
before_action :set_account, only: [:show, :edit, :new, :create]
before_action :set_subaccount, only: [:show, :edit, :update, :destroy]
def show
end
private
def set_account
#account ||= Account.find(params[:account_id])
end
def set_subaccount
#subaccount ||= #account.subaccounts.find(params[:id])
end
def subaccount_params
params.require(:subaccount).permit(:name, :state)
end
The issue you are facing is due to same controller action for 2 different routes. You can fix it by either adding another controller for nested route
resources :accounts do
resources :subaccounts, controller: 'accounts_subaccounts'
end
Or handle exception and check for #account (least preferred way / bad practice)
#account ||= Account.find(params[:account_id]) rescue nil
With handling with rescue you need to handle #account everywhere.
You can also trigger set_account method when params[:account_id].present? which will also work for you.

Rails routes: GET method redirecting to show method

I have simple controller and routes file.
In my route and controller i have created a module. I wrote a simple method which is redirecting me show. I am not sure why.
Controller
module Seller
class CampaignsController < Seller::BaseController
before_action :confirm_logged_in
def viewAllCampaigns
#campaigns = Campaign.all
end
def show
end
end
end
Routes file
scope module: 'seller' do
#namespace :power do
resources :dashboard, only: [:index]
resources :sessions, only: [:create, :destroy]
resources :campaigns, only: [:index, :create, :show, :update, :destroy]
get 'viewAllCampaigns' => 'campaigns#viewAllCampaigns'
end
Output
Started GET "/campaigns/viewAllCampaigns" for 127.0.0.1 at 2015-10-12 17:39:43 +0500
Processing by Seller::CampaignsController#show as HTML
Parameters: {"id"=>"viewAllCampaigns"}
Rendered seller/campaigns/show.html.erb (0.1ms)
I am hitting http://localhost:3000/campaigns/viewAllCampaigns in browser.
Ideally your routes should be defined like this.
resources :campaigns, only: [:index, :create, :show, :update, :destroy] do
get 'viewAllCampaigns', on: :collection
end
The first comment on the routes.rb file is The priority is based upon order of creation: first created -> highest priority. This is the reason your route is redirecting to show. Rails is treating this url as campain/:id.
Routes are tested in order, from top to bottom. The show route you've added for the campaigns resource will look for urls matching this pattern:
/campaigns/:id
/campaigns/viewAllCampaigns matches this, so it will do the show action., with params[:id] = "viewAllCampaigns"
Move the special case route up above the resources#campaigns route to fix this, then it will catch the url first.
get 'viewAllCampaigns' => 'campaigns#viewAllCampaigns'
resources :campaigns, only: [:index, :create, :show, :update, :destroy]
It takes the following get request as a show action because show expects campaigns/:id, and it assumes 'viewAllCampaigns' is an id in this instance:
/campaigns/viewAllCampaigns
Your link_to should just be pointing to the following:
'/viewAllCampaigns'
Your route structure isn't really RESTful, but that's a separate topic.

New route in resource generates instead of params[:id] params[:patient_id]

I added a new route to one of my resources:
resources :patients do
get 'warte'
end
This generates:
patient_warte_path GET /patients/:patient_id/warte(.:format) patients#warte
patients_path GET /patients(.:format) patients#index
new_patient_path GET /patients/new(.:format) patients#new
edit_patient_path GET /patients/:id/edit(.:format) patients#edit
patient_path GET /patients/:id(.:format) patients#show
.....
What i dont undestand is why the new route generated params[:patient_id!
I mean in my controller i have:
before_action :set_patient, only: [:show, :edit, :update, :destroy, :warte]
def set_patient
#patient = Patient.find(params[:id])
session[:patient] = #patient.id
end
But now of course i get the error: when i call the warte action! Thanks1
Couldn't find Patient without an ID
You are missing a configuration in order to have it use the id. You need to define if it's a :member or :collection action:
resources :patients do
get 'warte', on: :member
end

Resources