I am trying to create a delete button on my show page that shows the data of the selected recipe. My problem is every time I try to make a delete button i keep either getting path errors like "cant find the path recipe_path" or an error that says
/home/robert/recipe/app/views/recipes/show.html.erb:41: syntax error, unexpected tIDENTIFIER, expecting ')' ...pend=( link_to 'Delete' recipes, method: :delete );#output_b... ... ^~~~~~~"
if you need any more code or information please ask.
I have tried changing my path looking at others that had delete issues like this and watching several videos on deleting in ruby on rails but none of it has worked.
<button><%= link_to 'Delete' recipes, method: :delete
%></button>
def destroy
#recipes = Recipe.find(params[:id])
#recipes.destroy
end
for some permutations of the delete buttons I have made I have gotten either the error messages stated above or a button shows up that does nothing.
You are missing a comma between 'Delete' recipes in the arguments list:
<%= link_to 'Delete', recipes, method: :delete %>
Which solves the syntax error. However placing an <a> inside a <button> tag is invalid HTML.
Permitted content
Phrasing content but there must be no Interactive content
- MDN Web Docs: The Button element
Either just style a regular <a> with CSS to look like a button or create a discrete form with button_to:
<%= button_to 'Delete', recipes, method: :delete %>
Since you seem to be just flailing around you can get an example of the how to actually code this by running the scaffold generator.
$ rails g scaffold recipe title:string
Which generates:
# config/routes.rb
Rails.application.routes.draw do
resources :recipes
# For details on the DSL available within this file, see http://guides.rubyonrails.org/routing.html
end
# app/controllers/recipes_controller.rb
class RecipesController < ApplicationController
before_action :set_recipe, only: [:show, :edit, :update, :destroy]
# GET /recipes
# GET /recipes.json
def index
#recipes = Recipe.all
end
# ...
# DELETE /recipes/1
# DELETE /recipes/1.json
def destroy
#recipe.destroy
respond_to do |format|
format.html { redirect_to recipes_url, notice: 'Recipe was successfully destroyed.' }
format.json { head :no_content }
end
end
private
# Use callbacks to share common setup or constraints between actions.
def set_recipe
#recipe = Recipe.find(params[:id])
end
# ...
end
# app/views/recipes/index.html.erb
<table>
<thead>
<tr>
<th colspan="3"></th>
</tr>
</thead>
<tbody>
<% #recipes.each do |recipe| %>
<tr>
<td><%= link_to 'Show', recipe %></td>
<td><%= link_to 'Edit', edit_recipe_path(recipe) %></td>
<td><%= link_to 'Destroy', recipe, method: :delete, data: { confirm: 'Are you sure?' } %></td>
</tr>
<% end %>
</tbody>
</table>
Note that in Rails proper pluralization is very important as it ties in with the whole convention over configuration approach.
Related
UPDATE rephrased after learning
I have extended my app with a new model called 'tag' (very similar set up as with comments in blog).
Intended outcome: the user to stay on the page when clicking the link_to button to delete a tag; I now get an routing error (below) and I don't understand why.
No route matches [DELETE] "/annotations/7/tags"
The TAG list is added to the view for ANNOTATIONS like this:
<div class="panel panel-default" style="background-color: white; word-wrap: break-word; font-size: 0.9em;">
<table id="tags" class="table table-hover">
<thead>
<tr>
<th>Tag</th>
<th>Type</th>
<th></th>
</tr>
</thead>
<tbody>
<% #annotation.tags.each do |tag| %>
<tr>
<td><%= tag.content %></td>
<td><%#= tag.tagtype_id | tag.tagtype.typeoftag %></td>
<td><%= link_to '', [tag.annotation, tag], method: :delete, data: { confirm: 'Please confirm deletion!' }, :class => "glyphicon glyphicon-remove" %></td>
</tr>
<% end -%>
</tbody>
</table>
</div>
These are my routes:
Rails.application.routes.draw do
root 'dashboard#index'
devise_for :users
resources :users, :documenttypes, :tagtypes
resources :documents do
resources :tags
get "pdf", on: :member
end
resources :annotations do
resources :comments, :tags
get "pdf", on: :member
end
get "annotations/:id/annotate" => "annotations#annotate", as: 'annotate'
get "angular_test", to: "angular_test#index"
mount PdfjsViewer::Rails::Engine => "/pdfjs", as: 'pdfs'
And the tags.controller
class TagsController < ApplicationController
def create
#annotation = Annotation.find(params[:annotation_id])
#comment = #annotation.tags.create(tag_params)
redirect_to annotation_path(#annotation)
end
def destroy
#annotation = Annotation.find(params[:annotation_id])
#comment = #annotation.tags.find(params[:id])
#comment.destroy
redirect_to annotate_path(#annotation)
end
private
def tag_params
params.require(:tag).permit(:content, :location, :tagtype_id)
end
end
UPDATE
The table in the view always has an empty row, which I cannot delete. I then get the routing error. With rows that were created when adding a tag, this does not happen and I can delete them. Why am I getting an empty row?
This needs to be done using AJAX (asynchronously), all you need to do is to have your destroy action to respond to javascript. You can do that by adding the remote option to the link for the deletion as below:
<td><%= link_to 'Delete', [tag.annotation, tag], method: :delete, remote: true, data: { confirm: 'Please confirm deletion!' }, :class => "glyphicon glyphicon-remove" %></td>
The remote: true option makes the request AJAX. Now on the controller side you need to respond with the resulting javascript code that you want to execute, probably hiding this row that you want to delete.
In the views folder, under the tags controller you need to create a file called destroy.js and in this file you specify the code that you want to be executed for handling this to hide for example that row.
I have searched for hours, tried every possible fix. I cannot make this work. The error is:
*NoMethodError in Articles#index
Showing /Users/myname/blog/app/views/articles/showall.html.erb where line #21 raised:
undefined method `each' for nil:NilClass*
showall.html.erb is a view. It is rendered from the 'article' controller. (both posted below). There is a route to showall, and it works fine. Currently the route is configured as:
get 'article/showall'
But, I have also tried it as:
resources :articles do
get 'showall'
resources :comments
Both routes worked, but neither had an effect on the issue.
There is a method in the controller, its not private:
def showall
#articles = Article.all
end
The offending piece of code in the view is:
<% #articles.each do |article| %>
<tr>
<td><%= article.title.truncate(30) %></td>
<td><%= article.author %></td>
<td><%= article.manufacturer %></td>
<td><%= article.model %></td>
<td><%= article.displacement %></td>`
<% end %>
I actually cut and pasted, the piece of code from the index.html.erb view, where it works perfectly. I have tried every nuance of pluralization I can think of. Any help would be greatly appreciated.
This applicable parts of the controller:
class ArticlesController < ApplicationController
skip_before_action :authorize, only: [:index, :show, :showall]
#Filter used to catch nonlogged in users
before_filter :require_user, :only => [:index]
#method that checks if logged in, sends them to showall if not.
def require_user
unless User.find_by(id: session[:user_id])
render 'showall', :notice => "Please log in to read articles."
end
end
def index
#articles = current_user.articles
end
#should list articles, but throws undefined method 'each' error
def showall
#articles = Article.all
end
Here is the entire view:
<%= render "menu" %>
<body>
<font color="yellow"><%= flash[:notice] %></font>
<br>
<font color="grey">Motorcycle Articles</font>
<%= link_to 'Post New Article', new_article_path %>
<br>
<table>
<tr>
<th>Title</th>
<th>Author</th>
<th>Brand</th>
<th>Model</th>
<th>Displacment</th>
<th>Last Edited On:</th>
<th>Article</th>
</tr>
<% #articles.each do |article| %>
<tr>
<td><%= article.title.truncate(30) %></td>
<td><%= article.author %></td>
<td><%= article.manufacturer %></td>
<td><%= article.model %></td>
<td><%= article.displacement %></td>
<% end %>
</table>
<br>
All articles are property of their respective owners.
</body>
Route is triggering index action, see:
NoMethodError in Articles#index
You get the error because current_user.articles is nil.
You need to make sure Articles#showall is appearing in the log, that will mean that showall method is called.
Do that creating routes:
get '/articles', to: 'Articles#showall'
resources :articles
This is not recommended. There are several parts to improve. But it should make the error disappear.
You are calling render 'showall', which renders the view. This is different than 'redirect_to', which calls the controller action. Since you are setting the value of #articles with a nil value (current_user is not set), you get this error.
To clarify, you need to either redirect_to the 'showall' action or redefine #articles to equal Article.all before rendering the view. Personally I'd redirect.
Modify your routes file
routes.rb
resources :articles do
collection do
get 'showall'
end
end
I'm trying to add a delete action to my app, and I'm getting an odd error that I"m having trouble tracking down. It seems like the create action is being triggered even though I've assigned the button to the delete action. Based on the URL when I click on the delete button, it seems like it might be using GET, which I'm pretty sure isn't correct.
Any help is much appreciated!
Here's the error I'm getting when I click on a delete button in the index view.
class DogsController < ApplicationController
def create
Dog.create(dog_params)
#dogs = Dog.all
redirect_to dogs_path
end
def new
#dog = Dog.new
end
def edit
end
def delete
#dog = Dog.find params[:id]
#dog.destroy
redirect_to dogs_path
end
def show
#dog = Dog.find params[:id]
end
def index
#dogs = Dog.all
end
private
def dog_params
params.require(:dog).permit(:name, :breed)
end
end
And here's the code for the index view:
<h1>List of Dogs</h1>
<table>
<thead>
<tr>
<td>Name</td>
<td>Breed</td>
<td>Details</td>
</tr>
</thead>
<% #dogs.each do |d| %>
<tr>
<td><%= d.name %></td>
<td><%= d.breed %></td>
<td><%= d.id %></td>
<td><%= link_to 'Details', dog_path(d.id) %></td>
<td><%= link_to 'Edit', edit_dog_path(d.id) %></td>
<td><%= button_to 'Delete', :method => :delete %></td>
</tr>
<% end %>
</table>
Rails will be looking for destroy not delete in your controller.
Change def delete to def destroy
Aha also noticed you're not specifying what you want to delete:
<%= button_to 'Delete', d, :method => :delete %>
Also in your create you're getting all Dogs then redirecting which is a waste, remove the #dogs = Dog.all query.
#dogs = Dog.all
redirect_to dogs_path
button_to must pass in a parameter like this
button_to 'Delete', dog, method: :delete
I have two controllers: Tasksadmins and Workers.
I defined a table, is called: Tasksadmin, and has the parameters: admin_email, worker_email, task, done. the done option is check box.
in Tasksadmins controller, I defined:
def edit
#tasksadmin = Tasksadmin.find(params[:id])
end
in this controller, I can edit all the row of the table. it works fine!
in the Workerscontroller, I tried to define:
def edit
#tasksadmin = Tasksadmin.find(params[:id])
end
I did it because I want to get all of the parameters of the row, but I will let the worker an option to change only the parameter of done.
unfortunately, I got this error:
ActiveRecord::RecordNotFound in WorkersController#edit
Couldn't find Worker with id=15
I think I got it because the url is: localhost:3000/workers/15/edit
(pay attention to: workers/15/edit)
in order to understand where the problem is, I wrote the next word in my models/workers/edit.html.erb:
hello!
so I think the problem is with the work workers in the url :/
how can I fix it please?
UPDATE:
this is the index of the workerscontroller:
def index
#tasks_worker = Tasksadmin.where(:worker_mail => current_user.email)
respond_to do |format|
format.html # index.html.erb
format.json { render json: #workers }
end
end
this is index.html.erb:
<h1>Listing workers</h1>
<table>
<tr>
<th>Admin_mail</th>
<th>Task</th>
<th>Done</th>
<th></th>
<th></th>
<th></th>
</tr>
<% #tasks_worker.each do |task| %>
<tr>
<td><%= task.admin_mail %></td>
<td><%= task.task %></td>
<td><%= task.done %></td>
<td><%= link_to 'Edit', edit_worker_path(task) %></td>
</tr>
<% end %>
</table>
It seems like Worker with ID=15 doesn't exist.
Worker.find(params[:id])
Will raise ActiveRecord::RecordNotFound if that Worker doesn't exist.
You can go into the rails console and try:
Worker.find(15)
If you want to have find return nil instead of raising you can use:
Worker.find_by_id(params[:id])
I'm not too sure about this (maybe somebody can correct me), but I think
#tasksadmin = Tasksadmin.find(params[:id])
just defines the variable #tasksadmin.
Now, if you call the localhost:3000/workers/15/edit-URL, Rails is actually searching for a worker with ID 15 (Worker.find(15))
What do you want to accomplish?
I added this line in Workerscontroller:
load_and_authorize_resource :except => [:edit, :update]
and this line in Tasksadminscontroller:
load_and_authorize_resource :except => [:update, :show]
I'm currently trying to use a custom method in Rails and I do not know how to do so. Apart from the default methods in the controller, I wanted to add the following:
def cancel
#newsletter = Newsletter.find(params[:id])
respond_to do |format|
#SendGrid Newsletter API - Delete Newsletter Schedule
SendGrid.delete_schedule(#newsletter.name)
#newsletter.status = "CANCELLED"
#newsletter.save
format.html { redirect_to newsletters_url }
format.json { head :no_content }
end
end
The method is just like the default :destroy method but it doesn't actually destroys the object.
In my view, I had the following:
<% #newsletters.each do |newsletter| %>
<tr>
<td><%= newsletter.identity %></td>
<td><%= newsletter.name %></td>
<td><%= newsletter.recipients %></td>
<td><%= newsletter.subject %></td>
<td><%= newsletter.html %></td>
<td><%= newsletter.text %></td>
<td><%= newsletter.schedule %></td>
<td><%= newsletter.status %></td>
<td><%= link_to 'Show', newsletter %></td>
<td><%= link_to 'Edit', edit_newsletter_path(newsletter) %></td>
<td><%= link_to 'Destroy', newsletter, method: :delete, data: { confirm: 'Are you sure?' } %></td>
<td><% if newsletter.status == "SCHEDULED" %><%= link_to 'Cancel', newsletter, method: :cancel, data: { confirm: 'Cancel Schedule?' }%><% end %></td>
</tr>
<% end %>
I got the error: No route matches [POST] "_newsletter url__"
When I rake routes, there isn't any route for the error above. May I know how to add the route and why is the route needed?
UPDATE
Currently, I still have the no route matches error. Below are all my files related to the 'Cancel' method:
routes.rb
resources :newsletters do
match '/cancel/:id' => 'newsletters#cancel', :as => :cancel
end
newsletters_controller.rb
def cancel
#newsletter = Newsletter.find(params[:id])
respond_to do |format|
#SendGrid Newsletter API - Delete Newsletter Schedule
SendGrid.delete_schedule(#newsletter.name)
#newsletter.status = "CANCELLED"
#newsletter.save
format.html { redirect_to newsletters_path(#newsletter) }
format.json { head :no_content }
end
end
newsletters/index.html.erb
<%= link_to 'Cancel', newsletter_cancel_path(newsletter) %>
You should have a line like this in your config/routes.rb file
resources :newsletters
You'll want to change it to this
resources :newsletters do
member do
put 'cancel'
end
end
You'll want to take a look at the routing guide that Иван Бишевац posted. You'll also want to understand basic restful routing and how Rails handles GET, POST, PUT, DELETE, etc.
I think you're mistaking the method: argument in the link_to as corresponding to the method in the controller. Actually it is referring to the RESTful HTTP verb i.e. :post, :delete and :put. So you don't pass the controller action through this way.
Instead you can pass in :controller and :action arguments...
Better still create a route in routes.rb and use the path that rails generates.
match "/cancel/:id", to: "controller#cancel", as: :cancel
and then the link_to would be something like:
link_to 'Cancel', cancel_path(newsletter)
Update:
The error you're getting is with the redirect_to in your cancel method (in the controller). Change the newsletters_url to newsletter_path(#newsletter) instead.
If you want to redirect back to the show page for a single newsletter, then you need to do the above (where you pass in the #newsletter parameter), if you want it to go back to the newsletters index page then it'll be newsletters_path.
You can check the existence of the routes by typing rake routes in your terminal. You'll see all the route names there.
Do you still get an error after changing to redirect_to newsletter_path(#newsletter)?
The thing that doesn't quite strike true is that you're getting a no POST route defined - which usually points to a malformed form_for. Examine your newsletter related forms especially any where you don't do the regular form_for #newsletter do |f|.
Here is complete explanation about routing:
http://guides.rubyonrails.org/routing.html