0

I'm beginner at Rails, and im actually stuck with apparently a "beginner problem".

I got a "sounds" scaffolded controller, and i had to add an action "sendit". I can't have access to the sound from my view to my controller.

This is my error when i try to access to "http://127.0.0.1:3000/sounds/sendit.14" (Why it's sendit.14 and not sounds/sendit/14 or sounds/14/sendit ?)

ActiveRecord::RecordNotFound in SoundsController#sendit

Couldn't find Sound without an ID

Application Trace | Framework Trace | Full Trace
app/controllers/sounds_controller.rb:74:in `sendit'
Request

Parameters:

{"format"=>"14"}

Here is my code :

Sound Controller :

def sendit
    @sound = Sound.find(params[:id]) # ----- Error is on this line -----
    # Do Job
  end


Index.html.erb

<% @sounds.each do |sound| %>
  <% if sound.user_id == current_user.id %>
    <tr>
      <td><%= sound.title %></td>
      <td><%= sound.user.email %></td>
      <td><%= link_to 'Show', sound %></td>
      <td><%= link_to 'Edit', edit_sound_path(sound) %></td>
      <td><%= link_to 'Destroy', sound, method: :delete, data: { confirm: 'Are you sure?' } %></td>
      <td><%= link_to 'Send', sounds_sendit_path(sound) %></td>


routes.rb

  devise_for :users

  match "/sounds/sendit/", :controller => "sounds", :action => "sendit"

  resources :users, :sounds

I did this in the route file because of Adding an action to an existing controller (Ruby on Rails)


When i do rake routes , this is the output :

              [...]
           sounds_sendit        /sounds/sendit(.:format)       sounds#sendit 
                   users GET    /users(.:format)               users#index
                         POST   /users(.:format)               users#create
                new_user GET    /users/new(.:format)           users#new
               edit_user GET    /users/:id/edit(.:format)      users#edit
                    user GET    /users/:id(.:format)           users#show
                         PUT    /users/:id(.:format)           users#update
                         DELETE /users/:id(.:format)           users#destroy
                  sounds GET    /sounds(.:format)              sounds#index
                         POST   /sounds(.:format)              sounds#create
               new_sound GET    /sounds/new(.:format)          sounds#new
              edit_sound GET    /sounds/:id/edit(.:format)     sounds#edit
                   sound GET    /sounds/:id(.:format)          sounds#show
                         PUT    /sounds/:id(.:format)          sounds#update
                         DELETE /sounds/:id(.:format)          sounds#destroy
                    root        /                              home#index

(I actually don't understand the first line, why there is no POST / GET, and why it's sounds_sendit and no sendit_sound like others default actions? How to fix it? )

Thank you for your help

Community
  • 1
  • 1
Erowlin
  • 9,555
  • 4
  • 35
  • 63

3 Answers3

2

Because you don't have route to the action with id as param, so rails assumes that id is format You have to create route for that

resources :sounds do
  post :sendit, on: :member
end
Yuri Barbashov
  • 5,407
  • 1
  • 24
  • 20
  • What's the difference between your code and davidb code? You just dont specify the get || post? – Erowlin Jul 31 '12 at 09:49
  • It is just a little bit cleaner. You could use match over post, but if don't need all types of request just stick to one type – Yuri Barbashov Jul 31 '12 at 11:08
2

Instead of this :

match "/sounds/sendit/", :controller => "sounds", :action => "sendit"

Use this:

  resources :sounds do
    member do
      get :sendit
    end
  end

Then you will be able to use the sendit_sound_path helper to link to the action correctly:

link_to "link text", sendit_sound_path(sound_object)

Hope this does it for you,...

davidb
  • 8,884
  • 4
  • 36
  • 72
  • Worked like a charm, thank you a lot. ;) 2 days i was stuck on this problem, i promise i will read and learn all the route section on the rails doc ;) – Erowlin Jul 31 '12 at 09:48
  • he already did this have a look at the routes.rb posted above – davidb Jul 31 '12 at 10:24
1

You should define in your routes the id parameter, see here.

match "/sounds/:id/sendit/", :controller => "sounds", :action => "sendit"

You can name your route by using the 'as' option. An example from the above site:

match 'exit' => 'sessions#destroy', :as => :logout

If you only want a get, then you can use get instead of match. An example:

either:

match 'photos/show' => 'photos#show', :via => :get

or shorter:

get 'photos/show'
davidrac
  • 10,723
  • 3
  • 39
  • 71
  • Got a question : if instead of "/sounds/:id/sendit/" i wroted "/sounds/:somethingelse/sendit/", it should work? or the ":id" is interpreted like that? – Erowlin Jul 31 '12 at 09:40
  • It will just pass a parameter called :somethingelse in the params hash. the symbol :id is nothing magical. – davidrac Jul 31 '12 at 09:46