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
Related
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.
My method does not work.
I have a games library, where I can add, show, edit, and destroy. I want to expand it and add one more method clone to it.
Library created with rails g scaffold:
The clone method in games_controller.rb
def clone
#game.clone
respond_to do |format|
format.html { redirect_to games_url, notice: 'Game was successfully cloned.'}
format.json { head :no_content }
end
end
The call code for Clone in index
<% #games.each do |game| %>
<tr>
<td><%= game.title %></td>
<td><%= game.description %></td>
<td><%= link_to 'Show', game %></td>
<td><%= link_to 'Edit', edit_game_path(game) %></td>
<td><%= link_to 'Destroy', game, method: :delete, data: { confirm: '.. sure?' } %></td>
<td><%= link_to 'Clone', game, method: :clone, data: { confirm: '.. sure?' } %></td>
</tr>
<% end %>
The routes code in routes.rb
resources :games do
resources :comments
post 'clone'
end
a view in games library
You are doing it wrong. You have method: :clone which is not valid. The valid values for method option for link_to are post, patch, put and delete.
method: symbol of HTTP verb - This modifier will dynamically create an
HTML form and immediately submit the form for processing using the
HTTP verb specified. Useful for having links perform a POST operation
in dangerous actions like deleting a record (which search bots can
follow while spidering your site). Supported verbs are :post, :delete,
:patch, and :put. Note that if the user has JavaScript disabled, the
request will fall back to using GET. If href: '#' is used and the user
has JavaScript disabled clicking the link will have no effect. If you
are relying on the POST behavior, you should check for it in your
controller's action by using the request object's methods for post?,
delete?, patch?, or put?.
Now coming to your routes, when you do rake routes, you will see the below
game_clone POST /games/:game_id/clone(.:format) games#clone
So, the link_to should look like below
<%= link_to 'Clone', game_clone_path(game), method: :post, data: { confirm: '.. sure?' } %>
Couldn't find Game without an ID
Ok, you are cloning a Game instance. Normally you look for an instance with an :id, but with your current routes, the :game_id will passed in the params which is not appropriate to want you need. You should change your routes to pass :id instead of :game_id. So the final solution will be
Final Solution:
resources :games do
resources :comments
post 'clone', on: :member
end
The above will create a path helper with the below
clone_game POST /games/:id/clone(.:format) games#clone
Now change the link_to with the new path helper and you are good to go
<%= link_to 'Clone', clone_game_path(game), method: :post, data: { confirm: '.. sure?' } %>
Note:
You should be careful when adding custom routes to your resourceful routes. This will create path helpers with unnecessary keys such as :*_id(:game_id in your case). These routes should be added as collection route or a member route depending upon the scenario. For more info refer these guides
I have a model organismereferent which has a boolean value named active. What I'm trying to do is depending on what value it has do a different action.
So if it's active the button shows deactivate and allows the user to set active to false. So after that the button should show activate which will allow the user to set active back to true.
I tried making a method in my controller then calling that method from my index view but it gives me a No route matches [POST] "/organismereferents/8". I'm pretty new to Ruby on Rails so there must be an easier way to accomplish that
View:
<table class="table table-hover">
<tr>
<th>Nom Organisation</th>
<th>Site Web</th>
</tr>
<% #organismes.each do |organisme| %>
<tr>
<td><%= organisme.nom_organisation %></td>
<td><%= organisme.site_web %></td>
<td><%= link_to 'Show', organismereferent_path(organisme), class: 'btn btn-info' %></td>
<td><%= link_to 'Edit', edit_organismereferent_path(organisme), class: 'btn btn-warning' %></td>
<% if organisme.active == false %>
<td><%= link_to 'Activate', organismereferent_path(organisme), class: 'btn btn-danger',
method: :activate,
data: { confirm: 'Are you sure?' } %></td>
<% else %>
<td><%= link_to 'Deactivate', organismereferent_path(organisme), class: 'btn btn-danger',
method: :deactivate,
data: { confirm: 'Are you sure?' } %></td>
<% end %>
</tr>
<% end %>
</table>
Controller:
def index
#organismes = Organismereferent.all
end
def deactivate
#organisme = Organismereferent.find(params[:id])
#organisme.active = false
end
def activate
#organisme = Organismereferent.find(params[:id])
#organisme.active = true
end
If you need any more information I will be glad too add it.
Routes:
Rails.application.routes.draw do
# For details on the DSL available within this file, see http://guides.rubyonrails.org/routing.html
get 'master/index'
resources :organismereferents
# Notre page principal
root 'master#index'
end
We have a few problems here.
First, in your views, the link_to helper method parameter doesn't want to know the name of your controller action. It wants to know the http method to use. For the actions you are doing, I think the most appropriate would be PATCH. So change those lines to method: :patch.
Second, you need to update your routes.rb file to include the routes you need. You can do that by replacing resources :organismereferents with the following:
resources :organismereferents do
member { patch :activate }
member { patch :deactivate }
end
Using the member designation indicates to Rails that you want to include an :id param in the URL. Now when you run rake routes you should see, in addition to what you already have, the following:
activate_organismereferents PATCH /organismereferents/:id/activate(.:format) organismereferents#activate
deactivate_organismereferents PATCH /organismereferents/:id/deactivate(.:format) organismereferents#deactivate
Third, you need to fix your path helpers. The first column returned by rake routes tells you the name of the Rails helper path that you can use in your link_to helpers. So in your Activate link, you'll need to change organismereferent_path(organisme) to activate_organismereferent_path(organisme), and in your Deactivate link, use deactivate_organismereferent_path(organisme).
Finally, in your controller actions, you are not saving the records after you change the boolean value. You will need to call #organisme.save to persist the change. Or if you would prefer to make the change and save it in a single line, you can use #organisme.update(active: true) and #organisme.update(active: false).
This is my first project in rails, which is to create a table that will store data about games. I'm able to display data from the table about winner score, loser score, etc. However, I have issues with my table column that contains delete links for each game.
Here's my code in the games controller for the delete method:
def delete
#game = Game.find(params[:game])
#game.destroy()
redirect_to :action => 'index'
end
A snippet of my table code, which includes the line for the link_to command
<% #games_items.each do |t| %>
<tr>
<td><%= t.winner.name %></td>
<td><%= t.loser.name %></td>
<td><%= t.challenger.name %></td>
<td><%= t.winner_score %></td>
<td><%= t.loser_score %></td>
<td><%= link_to 'Delete', delete_game_path(id: t.id)%></td>
</tr>
<% end %>
In the routes file I called
resources :games
Which, to my knowledge, helps generate the base routing. Could anyone help me figure out why my link_to is not working?
If you use (which is adviced) resources:
a) Your action for deleting records should be named destroy.
b) Game is searched for with :id parameter:
def destroy
#game = Game.find(params[:id])
#game.destroy
redirect_to :action => 'index'
end
c) Your link should be:
<%= link_to 'Delete', t, method: :delete %>
since the path is the same as for the show action, the only thig that changes is HTTP method.
The format for the delete call is:
<%= link_to 'Delete', game_path(t.id), :method => :delete %>
use rake routes to learn about the available routes, including generated route helpers, and the controller/action handling the request.
I had similar issue on rails 4.2.1, even with the :method => :delete on link_to it still routes to show method.
But using button_to method as below works!
<%= button_to "delete", article_path(:id => article.id), :method => :delete %>
button_to creates a form around the button and then posts to the delete method, by adding a hidden field named _method with value delete rails uses this to route to the destroy method in your controller.
Try to use <script src="https://ajax.googleapis.com/ajax/libs/jquery/1.12.0/jquery.min.js"></script> before <%= javascript_include_tag "application" %> in your layout, and also delete
//= require jquery
line in your application.js.
This was the case for me. No idea why it didn't worked with original rails jquery.js file.
I am trying to simply create a button that will delete a contact from a list of contacts.
At the moment I have the following setup:
Contacts Controller
def destroy
#user.contacts.delete(params[:contact])
#contact.delete
end
View
<tbody>
<% #contacts.each do |contact| %>
<tr>
<td><%= contact.name %></td>
<td><%= contact.company %></td>
<td><%= contact.email %></td>
<td><%= contact.phone %></td>
<td><%= contact.mobile %></td>
<td><%= button_to 'Delete', contact, :method => :delete %></td>
</tr>
<% end %>
Routes
controller :contact do
get "newcontact" => "contact#new"
get "index" => "contact#index"
delete "delete" => "contact#destroy"
end
I have read online that using button_to is the preferred method but at the moment I am getting the following error:
undefined method `contacts' for nil:NilClass
It would be great to get any feedback that might help me fix this.
Thanks in advance
Tom
For anyone looking for the final answer on this it was
def destroy
contact = current_user.contacts.find(params[:id])
contact.destroy
redirect_to index_path
end
In my controller and the following in my view
<%= button_to 'Delete', contact, :method => :delete %>
Thanks
Tom
If you are goin to use #user you need to set #user in your delete method or else it will be nil - hence the error message
The other issue is that the id of the contact is params[:id] and not params[:contact]
I'd just do
contact = current_user.contacts.find(params[:id])
contact.destroy
You definitely want to be deleting the contact via the user or else people can delete other users' contacts. This deletes the contact and removes it from the association - you don't need to do anything else
try something like this:
button_to "Delete", { :action => "delete", :id => contact.id}, :method => :delete
If #user is only defined in create it's only going to exist for requests that call create—and I'm guessing you're not calling create right before destroy. Each browser request creates a new instance of the controller; instance variables like #user don't stick around between requests.
To make it work, you probably just need this:
def destroy
Contact.delete params[:contact]
end
(When you delete a contact it will automatically be removed from e.g. current_user.contacts assuming your relations are set up in the usual way.)