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).
Related
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 want to write a method that changes a WorkShift to booked:true and booked_by:current_member.member_id. However I get the error
"undefined method `book' for #< WorkShift:0xc973ce0>"
and I don't understand why. I just want it to be a button and not a separate edit view.
Edit: Turns out I put the book method in the wrong place, but the same method in work_shifts.rb throws a "undefined method `to_model' for true:TrueClass" instead. I'm (obviously) unsure what is the correct way to call a custom method that updates one object with the params of another from a view.
My index view:
<% #work_shifts.each do |work_shift| %>
<tr>
<td><%= work_shift.date %></td>
<td><%= work_shift.booked_by %></td>
<td><%= work_shift.booked %></td>
<td><%= work_shift.start_time.strftime("%H:%M") %></td>
<td><%= work_shift.stop_time.strftime("%H:%M") %></td>
<td><%= button_to 'Book', work_shift.book(current_member) %></td>
<% if current_member.admin? %>
<td><%= link_to 'Edit', edit_work_shift_path(work_shift) %></td>
<td><%= button_to "Ta bort", work_shift, :method=>:delete, :work_shift=>:destroy %></td>
<% end %>
</tr>
<% end %>
WorkShift.rb:
def book(member_id)
self.update(booked:true, booked_by: member_id)
end
routes.rb
resources :work_shifts do
member do
get 'book'
end
end
I'm new to rails and learning on the go, and I'm guessing the solution is trivial, but I just can't find any questions or documentation that helps with what I want to do.
Since you're trying to modify a resource's single field, the book link should be a PATCH request and not GET.
Change your routes to
resources :work_shifts do
member do
patch 'book/:member_id' => 'work_shifts#book', as: 'book'
end
end
This will generate the following route
book_work_shift PATCH /work_shifts/:id/book/:member_id(.:format) workshifts#book
And update your book action as
def book
#work_shift = WorkShift.find(params[:id])
#work_shift.book(params[:member_id])
# redirect to some view
end
And modify your model method accordingly.
def book(member_id)
self.update(booked:true, booked_by: member_id)
end
And replace the your view from
<%= button_to 'Book', work_shift.book(current_member) %>
to a link (You can style it as a button if you want)
<%= link_to 'Book', book_work_shift_path(work_shift, current_member.member_id), method: :patch %>
Thats it!
I'm using Rails 4
I need to delete association Box with link_to method. The problem is that I have to do it from parrent controller and method: patch. my corrent code is doing nothing because I don't know how to use data: for link_to.
#views/modifications/show.html.erb
<% #modification.boxes.each do |box| %>
<tr>
<td><%= box.name %></td>
<td><%= link_to "delete", #modification, remote: true, method: :patch %></td>
</tr>
<% end %>
By the way, this is used with Ajax so page doesn't need to be reloaded.
I have to do it
You don't have to do anything in any way - if Microsoft can release Windows for all the PC's in the world, I'm sure you can get this working.
You have several issues, the most important of which being... how do you identify the box object to delete?
The whole point of nested resources (which is what you need) is to give you the ability to identify a "parent" object and a child object.
Your current setup prevents you from identifying the box you wish to remove. Ideally, you should use the following code to get it sorted:
#config/routes.rb
resources :modifications do
resources :boxes, only: :destroy
end
#app/views/modifications/show.html.erb
<% #modification.boxes.each do |box| %>
<tr>
<td><%= box.name %></td>
<td><%= link_to "delete", [#modification, box], remote: true, method: :delete %></td>
</tr>
<% end %>
#app/controllers/boxes_controller.rb
class BoxesController < ApplicationController
def destroy
#modification = Modification.find params[:modification_id]
#box = #modification.boxes.find params[:id]
#box.destroy
end
end
Try to using link_to with delete method on box destroy path, like this:
<%= link_to 'Delete', box_path(box), method: :delete, remote: true %>
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'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