Unknown action No action responded to delete. Actions: add, edit, and index - ruby-on-rails

When I am on the index page and click on the delete link to destroy the post i get that error:
Unknown action
No action responded to delete. Actions: add, edit, and index
The edit link next to delete works with out a problem I do not understand why delete won't work. This is what is in my controller car_controller.rb
def delete
#car = Car.find(params[:id])
flash[:notice] = "Question #{#car.name} deleted!"
#car.destroy
redirect_to :controller => :car, :action => :index
end
map.connect ':controller/:action/:id'
map.connect ':controller/:action/:id.:format'
map.root :controller => "main"
map.root :controller => "car"
end

Isn't the action for delete actually destroy?
If you look at a controller that was generated as part of scaffold, you should see what the delete action maps to...
Rails provides the 7 classical RESTful actions out of the box when you generate the controller and each one has the actual URL + method commented above the action method...
# DELETE /subject_families/1
# DELETE /subject_families/1.xml
def destroy
...
end
I hope this helps...

Make sure your request is using the correct HTTP verb. Rails' default for REST resources is to use HTTP DELETE on the destroy action. Are you using GET (a simple link) or POST instead of DELETE?
I recommend checking your routes - run rake routes - to confirm what Rails is expecting. If you are using Rails' resources route generator, then I would expect your view template to contain something like this:
<%= form_for #car, :html => { :method => :delete } do |f| %>
<%= submit_tag 'Delete Car' %>
<% end %>

Related

Controller/Action not found although physically present?

My attempt to make a new-action which gives the user a form and a create-action to process it fails with the error message `.
View: app/views/studios/new.html.erb:
<%= form_for #studio, url: {action: 'create'} do |f| %>
<%= f.text_field :name %>
<%= f.submit 'Create' %>
<% end %>
Controller: app/controllers/studio_controller.rb:
def new
#studio = Studio.new
respond_to do |format|
format.html
format.json { render json: #studio }
end
end
def create
# TODO
end
Route: config/routes.rb
get 'studios/new' => 'studios#new', :as => 'new_studio'
On attempting to visit http://localhost:3000/studios/new, I am presented with the error
No route matches {:action=>"create", :controller=>"studios"}
As you can see, the create-action is present in the studios-controller. Why is it failing?
It's failing because you don't have route defined for the create action. You have a get action defined for the new action only.
Update your routes file to add a post route to the create action as:
post 'studios/create' => 'studios#create'
Or, you could choose to use resourceful routing and update your routes file as:
resources :studios, only: [ :new, :create ]
This will define the new and create route for your studio resource. To see the generated routes you can run rake routes.
The rails form helper, given the instance variable #studio, asks for the instance variable via the new action, and, upon clicking save, calls the create action to validate and save this new instance. It's failing because rails cannot find the action to submit the object to.
Try adding resources :studios for RESTful routes in config/routes.rb (index, new, create, show, edit, update, destroy) automagically routing to actions with the same name in the app/controllers/studio_controller.rb
Try visiting the docs for form helpers here: http://guides.rubyonrails.org/form_helpers.html#binding-a-form-to-an-object for a more in depth explaination.

Rails - custom action in controller - how to reference in view?

I'm using a custom action to get the id of a project into the session, so that only relevant info for that project is shown in other areas. I've made a custom action in the projects controller, and am having trouble getting a link to work in the view to call that action. I just get an error saying "Couldn't find project without ID". I'm new to rails - I know it's probably an easy question, but help would be much appreciated, thanks!
View Code:
<%= link_to 'Select Project', :action => :select_project %>
Controller Code:
def select_project
#project = Project.find(params[:id])
session[:project_id] = #project.id
end
Routes:
resources :projects do
collection do
get :select_project
end
end
Alternative routes code:
resources :projects do
put 'select_project', on: :member
end
This is untested but I believe it is what you are looking for:
Routes:
resources :projects do
member do
post :set_current
end
end
this should create the following:
Endpoint: /projects/:id/set_current POST
Helper: set_current_project_path
Controller
def set_current
project = Project.find(params[:id])
session[:project_id] = project.id
redirect_to projects_path, :notice => "Current project set to #{project.name}"
end
Views
# index / erb tags excluded for simplicity
#projects.each do |project|
link_to 'Select Project', set_current_project_path(project), :method => :post
end
# show
<%= link_to 'Select Project', set_current_project_path(#project), :method => :post %>
See:
http://guides.rubyonrails.org/routing.html#adding-more-restful-actions
http://guides.rubyonrails.org/routing.html#crud-verbs-and-actions
Note also the use of 'post' instead of 'get', since we are changing the state of an object (session)
it is preferred to use a post not a get, otherwise users might pull up an old get request in the address bar
of their browser and set their session to a project unknowingly.
like varatis said - use rake routes or CONTROLLER=projects rake routes to help with determining what your route/path helpers look like and what http verbs they are expecting
And is there a reason why it's project not #project in the controller
The #project creates an instance variable; in a rails controller instance variables are made available to the views. This set_current action will never render a view, so no reason to make an instance variable out of it.
How come you have to set it to member and not collection in the routes
any action where you want to reference params[:id] should be a member route, an alternative would be to leave it as a collection route and pass params[:project_id] and pass that in all of your link_to calls, but in this case member makes more sense.
I believe resources :projects is a short cut for this break down
member do
get :show
get :edit
put :update
delete :destroy
end
collection do
get :index
get :new
post :create
end
hopefully that clarifies your questions some?
I think the route generated would be select_project_projects_path.
Link:
<%= link_to 'Select Project', select_project_projects_path %>
For future reference, run rake routes to see the automatic route helpers generated by Rails.

Rails not finding controller action

So, I have the following link-to:
<%= link_to(outing_add_guests_path, :class => 'modal') do %>
<div id="notImportant"></div>
<% end %>
When I click on it, Rails tells me that
No route matches {:controller=>"outings", :action=>"add_guests"}
However, here's my routes file:
resources :outings do
get "/add_guests" => "outings#add_guests"
post "/add_guests" => "outings#add_guests"
delete "/remove_guests" => "outings#remove_guests"
end
and the corresponding action from my Outings Controller:
def add_guests
#outing_guest = OutingGuest.new(:outing_id => params[:outing_id])
#outing_guest.user_id = params[:user_id]
if #outing_guest.save
flash[:notice] = "Guest added successfully"
redirect_to({ :action => 'outing', :id => params[:outing_id] })
else
flash[:notice] = "Guest could not be added"
redirect_to({ :action => 'outing', :id => params[:outing_id] })
end
end
Is there any reason Rails would be unable to detect my controller or its actions?
EDIT: Here's part of the results from rake routes
outing_add_guests GET /outings/:outing_id/add_guests(.:format) outings#add_guests
POST /outings/:outing_id/add_guests(.:format) outings#add_guests
I notice your link_to is not consistent with the other routes
outing_add_guests_path
outings_add_guests_path
Did you do rake routes to verify that outing_add_guests_path exists?
EDIT:
Your rake routes shows you need an outing_id so your routes aren't setup right (at least not for the POST). I'd fix them the way #RyanBigg is suggesting.
You should be defining these routes using the collection method:
resources :outings do
collection do
get :add_guests
post :add_guests
delete :remove_guests
end
end
What this will do is define new routes for the specified actions, as well as automatically defining the routing helpers for those routes. For more information please read the Routing Guide.

Force current_user path

Currently users can access their "profile" through many paths.
localhost:3000/users/current_user
localhost:3000/users/current
localhost:3000/users/id#
How can I make it that they can only get to their "profile" through localhost:3000/users/current_user
One suggestion on the 'what' of your question: instead of the ideal url being localhost:3000/users/current_user I suggest localhost:3000/user or something even more descriptive such as localhost:3000/profile or localhost:3000/account.
Could you include the entries in your routes.rb? Even if Authlogic, etc. add routes to your app, they should do it in routes.rb. If you have the entry:
map.resource :users
then that's where the /users/123 route is coming from. I agree with Matchu that even if you don't use /users/123 you should keep it and route other requests to it.
An Additional Idea
If you don't want to get into the (kinda complicated, and not pretty) business of preserving model validation errors across redirects, here's another way. I'm assuming from here that you already have map.resource :users, so that you have the 7 default actions on your UsersController (index, new, create, show, edit, update, destroy).
In your routes.rb:
map.profile 'profile', :controller => 'users', :action => 'show'
map.edit_profile 'profile/edit', :controller => 'users', :action => 'edit', :conditions => { :method => :get }
map.update_profile 'profile/edit', :controller => 'users', :action => 'update', :conditions => { :method => :put }
You will need to update your form_for tag slightly:
<% form_for #user, :url => update_profile_path do |f| %> ...
Now, assuming you start on /profile, and click an edit link that takes you to /profile/edit (should show the form), if you fill out the form such that it fails validation then you should end up back on /profile/edit with the correct errors in the f.error_messages output.
Your controller code for edit should stay the same, and your code for update should be:
def update
#user = current_user || User.find(params[:id])
if #user.update_attributes(params[:user])
flash[:notice] = "Successfully updated user."
redirect_to #user
else
render :action => 'edit'
end
end
The render (rather than a redirect) preserves the state of the #user model (including errors) and just renders the edit template again. Since you directed it at the update_profile_path the url viewed by the user is still /profile/edit.
Umm, first, remove the /users/current route that you must have in your routes.rb somewhere. (Although I prefer /users/current to /users/current_users, since the latter is rather redundant.)
As for /users/123, in your controller, you can check if the current user's ID matches 123 or whatever, and, if so, redirect.
But I really prefer the opposite effect. Pushing /users/current to /users/123 makes more sense in my brain, since it keeps the routes consistent for all users while still allowing you to cache links to /users/current.

Ruby on Rails: Using a "complete_tasks_controller" for RESTful Rails

I'm having troubling completing a task the RESTful way. I have a "tasks" controller, and also a "complete_tasks" controller.
I have this in the complete_tasks_controller create action:
def create
#task = Task.find(params[:id])
#task.completed_at = Time.now
#task.save
end
I tried calling this:
<%=link_to "Complete task", new_task_complete_task_path(#task), :method => :post %>
..but I'm getting errors on that mentioning that "Only get, put, and delete requests are allowed."
Do you know what I'm doing wrong?
It would make more sense to move this into an action called complete in your controller:
def complete
#task = Task.find(params[:id])
#task.complete!
end
To access this action using RESTful routing you'll need to define a new member route like this in config/routes.rb:
map.resources :tasks, :member => { :complete => :put }
Adding :member => { :complete => :put } to the end of any pre-existing map.resources :tasks will do the trick also, you should only ever have one map.resources :tasks line, unless it's nested. The routing guide explains this better than I ever could.
To get to it from the view:
link_to "Complete this task", complete_task_path(#task), :method => :put
The method complete! would then be defined in your model like so:
def complete!
self.completed_at = Time.now
save!
end
The reason for this is that it puts the model logic where it belongs: in the model.
Each map.resources statement routes.rb creates a common RESTful routes for use with the specified resource. The appeal of REST is that is uses the request type and url to determine which action to take. Out of the four verbs associated with HTTP, each one has a specific use.
POST => Create
GET => Retrieve
PUT => Update
DELETE => Destroy
The reason you're getting an error about only get, put, and delete requests being allowed, is that you're using a post request. Essentially you're telling Rails you want to create a task with an id of one. However you cannot create an item that already exists. Which is why posts are not allowed. Instead you want to use put, because you're updating an existing record.
You can do it by changing post, to put in your link_to call.
<%=link_to "Complete task", new_task_complete_task_path(#task), :method => :put %>
Have a read through the routing guide and the resources documentation, it will help you understand the difference between HTTP requests, as well as provide some insight into how Rails handles those requests.

Resources