Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Rails 4 - how do I add an index route for a nested resource, in order to list all items independent of parent resource

I've got a nested resource Bar that belongs to Foo. I can successfully list all Bar objects that belong to any given Foo. But I also want to be able to generate a view with all Bar items listed together, from whatever Foo object they belong to.

The model structure is:

# app/models/foo.rb
class Foo < ActiveRecord
  has_many :bars
end

# app/models/bar.rb
class Bar < ActiveRecord
  belongs_to :foo
end

The routing is defined as:

# config/routes.rb
resources :foos do
  resources :bars
end

I get the expected routes from this configuration:

   foo_bars GET    /foos/:foo_id/bars(.:format)      bars#index
            POST   /foos/:foo_id/bars(.:format)      bars#create
new_foo_bar GET    /foos/:foo_id/bars/new(.:format)  bars#new
   edit_bar GET    /bars/:id/edit(.:format)          bars#edit
        bar GET    /bars/:id(.:format)               bars#show
            PATCH  /bars/:id(.:format)               bars#update
            PUT    /bars/:id(.:format)               bars#update
            DELETE /bars/:id(.:format)               bars#destroy
       foos GET    /foos(.:format)                   foos#index
            POST   /foos(.:format)                   foos#create
    new_foo GET    /foos/new(.:format)               foos#new
   edit_foo GET    /foos/:id/edit(.:format)          foos#edit
        foo GET    /foos/:id(.:format)               foos#show
            PATCH  /foos/:id(.:format)               foos#update
            PUT    /foos/:id(.:format)               foos#update
            DELETE /foos/:id(.:format)               foos#destroy

What I need is to generate a route for bars#index that isn't scoped within the context of foo. In other words, I essentially want:

bars  GET    /bars(.:format)      bars#index

I've tried using the shallow option, thus:

# config/routes.rb
resources :foos, shallow: true do
  resources :bars
end

However, this doesn't support the :index action, per the documentation.

What's the best way to do this? There's a helpful Stack Overflow discussion here, using a before_filter to determine scope -- but it's from 2009. Appreciate any specific guidance on how to set up both the controller and the config/routes.rb file appropriately!

like image 367
Scro Avatar asked Aug 01 '15 00:08

Scro


1 Answers

If you want to keep the scoped index method foo_bars and a separate bars route/view:

Create a custom route in routes.rb:

get 'bars' => 'bars#index', as: :bars

Set up your index method in your bars controller as described in your link or simply:

def index
  if params[:foo_id]
    @bars = Foo.find(params[:foo_id]).bars
  else
    @bars = Bar.all
  end
end

Then create a bars view directory (if you don't have one) and index.html.erb.


If you don't want to keep the scoped index method foo_bars:

Create a custom route in routes.rb:

get 'bars' => 'bars#index', as: :bars

Edit your existing routes to exclude the nested index:

resources :foos do
  resources :bars, except: :index
end

Then the bars controller could just be:

def index
  @bars = Bar.all
end

Then create a bars view directory (if you don't have one) and index.html.erb.

like image 58
Joseph Avatar answered Oct 30 '22 07:10

Joseph