user9926018
user9926018

Reputation:

Rails thinks a new route is an id and tries to use #show method

I have a database full of text_message records. I am trying to create a custom "list all text messages" page.

Here is my relevant part of my routes.rb file:

resources :text_messages
get '/text_messages/all_messages', to: 'text_messages#all_messages'

I have the standard RESTful controller methods, then my own all_messages method:

def all_messages
  @text_messages = TextMessage.order('send_time desc')
end

However, whenever I visit "localhost:port/text_messages/all_messages", I get an error:

ActiveRecord::RecordNotFound in TextMessagesController#show

Couldn't find TextMessage with 'id'=all_messages

So, Rails is getting something after 'text_messages/' and automatically assuming it is an id, even thought it is a string, and is completely ignoring my route. How do I get it to use me route and not try to use show()?

I am using Rails 4.2.

Upvotes: 1

Views: 1349

Answers (2)

Manishh
Manishh

Reputation: 1484

It is just because you have defined

resources :text_messages

before

get '/text_messages/all_messages', to: 'text_messages#all_messages'

by default resources add one route

get '/text_messages/:id'

which goes to the show action. this id can be any word or anything. currently when you are trying to call your all_messages it consider all_messages as id and goes to your show action and generate the error.

You can resolve this in 2 ways :

Move your custom route above the resources something like below:

get '/text_messages/all_messages', to: 'text_messages#all_messages'
resources :text_messages

Use collection with resource as

resources :text_messages do
  get 'all_messages', on: :collection
end

or

resources :text_messages do
  collection do
    get 'all_messages'
  end
end

Upvotes: 3

Sovalina
Sovalina

Reputation: 5609

You need to use the collection method:

This will enable Rails to recognize paths such as /text_messages/all_messages with GET, and route to the all_messages action of TextMessagesController. (source)

Change your routes like that:

resources :text_messages do
  get 'all_messages', on: :collection
end

Without collection, any route like 'text_messages/<a parameter>' hits the "show" action.

Upvotes: 1

Related Questions