I am trying to call a controller action on the link on rails app.
The controller action basically creates a new phone number and generates a Twilio pin.
controller
def resend
#phone_number = PhoneNumber.find_or_create_by(phone_number: params[:phone_number][:phone_number])
#phone_number.generate_pin
#phone_number.send_pin
respond_to do |format|
format.js # render app/views/phone_numbers/create.js.erb
end
end
view
Resend Pin
routes.rb`
post 'phone_numbers/resend' => "phone_numbers#resend"
So when I click "Resend Pin". I am getting
No route matches [GET] "/phone_numbers/resend"
rake routes output
phone_numbers POST /phone_numbers(.:format) phone_numbers#create
new_phone_number GET /phone_numbers/new(.:format) phone_numbers#new
phone_numbers_verify POST /phone_numbers/verify(.:format) phone_numbers#verify
phone_numbers_resend POST /phone_numbers/resend(.:format) phone_numbers#resend
In routes, I have set it as a post. Why am I getting this? How can I fix this?
link_to "Send Pin", phone_numbers_resend_path, method: :post
Anchor tag(<a>) by default uses get request . But in routes, you are using post method. So, to make it working you can do any one of the below:
<%= link_to 'Resend Pin', phone_numbers_resend_path, method: :post %>
or
get 'phone_numbers/resend' => "phone_numbers#resend"
Related
I'm trying to create a view with a button calling a controller action for a Redmine Plugin (unfortunately, I'm quite new at Rails). I'd need to create a method for my controller (here A Controller) so i can update some Active Records.
I created a controller:
redmine_a_controller.rb
class RedmineAController < ApplicationController
def prova(input)
puts input
return input
end
def p
puts 'vuoto'
returns 'vuoto'
end
end
The actions work correctly when called from the console. Unfortunately, when called from my view _a.html.erb:
<%=
button_to l(:imp_update), {
:controller => 'RedmineAController',
:action => 'p',
method: :post
}
%>
It returns this error:
ActionView::Template::Error (No route matches {:action=>"p", :controller=>"RedmineAController", :id=>"prova", :method=>:post, :tab=>"important_users"}):
I tried by calling the action on a new instance:
<%=
button_to l(:imp_update), {
:action => RedmineImportantUsersController.new.prova(1),
method: :post
}
%>
but it looks for the action in the Projects controller
ActionView::Template::Error (No route matches {:action=>"1", :controller=>"projects", :id=>"prova", :method=>:post}):
How can I make button_to call the correct prova method in the RedmineAController controller?
Thanks in advance for any help.
Add routes in routes.rb file
resources :redmine_as do
collections do
post :a
end
end
After that, Please fine the Routes url by typing on terminal below command
rake routes | grep p
Set the url in Link or button
link_to "Your Link Name", p_redmine_as_path
p_redmines_path it will be return by that "rake routes
| grep p" command.
As Ketan indicated, I was missing a route!
I put in my routes.rb:
resources :important_user do
collection do
post :u_update
end
end
and in my controller:
def u_update
puts params[:p_id]
puts "update!"
end
I am trying to call a method in a controller from a button in a Rails view. I followed some other questions on here and got to this point.
routes.rb:
namespace :processing do
resources :applications do
stuff
post :test, :to => 'applications#test', :on => :member
end
end
the controller method is simply called test. Here is the relevant part of the controller:
def test
#application = Application.find_by(record_id: params[:id])
puts 'THIS IS A TEST'
end
Finally, I am calling the route with this code in an .erb file:
<%= button_to 'Send to Processing',
test_processing_application_path(record_id),
method: :post, form_class: 'btn btn-danger' %>
The button renders properly and seems to follow the right route. However, my problem is that the button attempts to redirect and render the route
/processing/applications/715707082/test which doesn't exist and causes a problem.
How do I just make this button not redirect/render something and instead simply call the method from the page it is currently on? Please feel free to link me relevant posts or close this if it duplicates an existing question.
The route in your routes.rb file does define the
test_processing_application_path as a POST to the path
/processing/applications/:id/test(.:format)
expecting to be implemented in the controller
processing/applications#test --
that is a file in app/controllers/processing/applications_controller.rb that defines a controller like:
module Processing
class Applications < ApplicationController
def test
# your code here
end
end
end
Instead of using a method you should use action and remote true will trigger an ajax request and prevent you from redirection. Then create a test.js.erb file for handling ajax request to update your DOM that will be executed after your action call.
<%= button_to 'Send to Processing',test_processing_application_path(record_id),
action: :test, form_class: 'btn btn-danger', :remote=>true %>
Hope this will help.
Cheers.
I am new in Ruby and Rails and little bit confused about rendering and adding routes for a new template.
I have following link_to tag
<td colspan="3">
<%= link_to 'Show Current State', simulation, :action => :current_state, :class => 'btn btn-primary'%>
</td>
Where simulation is the name of controller and action is name of the method in SimulationController.
I added this in my routes.rb
resources :simulations, except: [:edit]
resources :simulations do
collection do
get 'current_state'
post 'current_state'
end
end
In my SimulationController class I added a new method i.e.
def current_state
byebug
end
My problem? routes is not re-directing to current_state method. Instead, it is redirecting to http://localhost:3000/simulations/{someID}
This redirection is calling show action.
def show
...
end
How can I make this work out and make <%= #simulation.dat %> line accessible in new.html.erb. Location of new.html.erb is in following path
views/simulations/index.html.js
views/similations/show.html.js
views/simulations/new.html.erb
This could be a basic question but I am new to rails 4. Thanks in advance.
Edit-1
Def of get_state method in controller
def get_state
#simulation = current_user.simulations.find(params[:id])
return not_found if #simulation.nil?
.....
/// How to send `#simulation` into `state.html.erb` formally as `new.html.erb`
end
You have too many misses in your code.
First, You don't need 2 resources :simulations, just merge them into one:
resources :simulations, except: :edit do
member do
get 'current_state', action: 'get_state'
post 'current_state', action: 'change_state'
end
end
Note that the original collection block is changed to a member block.
The difference between a collection block and a member block is that you need to provide an resource id for each routes in the member block, while no resource id is required for those in the collection block.
Also note that I added action: 'xxx' in each route, so you have to add these 2 actions in your SimulationsController, one for GET requests, and the other for POST requests.
UPDATE
In both of these actions, add render 'new' at the end.
END OF UPDATE
Run rake routes in your console (or bundle exec rake routes if you have multiple versions of rails installed), and you will see all the routes along with there url helper methods listed, like this:
Prefix Verb URI Pattern Controller#Action
current_state_simulations GET /simulations/:id/current_state simulations#get_state
current_state_simulations POST /simulations/:id/current_state simulations#change_state
...
According to the Prefix column, the link in the view should be
<%= link_to 'Show Current State', current_state_simulations_path(simulation), :class => 'btn btn-primary'%>
Or in short
<%= link_to 'Show Current State', [:current_state, simulation], :class => 'btn btn-primary'%>
UPDATE FOR Edit-1
Don't return in actions, because return doesn't stop rendering.
Instead, use raise ActionController::RoutingError.new('Not Found') to redirect users to the 404 page.
You can define an instance method in ApplicationController:
class ApplicationController < ActionController::Base
private
def not_found!
raise ActionController::RoutingError.new('Not Found')
end
end
And modify your SimulationsController:
def get_state
#simulation = current_user.simulations.find(params[:id])
not_found! unless #simulation
# ...
render 'new'
end
Best Practice
For dynamic page web applications, don't render views for non-GET requests!
Why? Because if a user POSTs some data to your web app, and then refreshes his/her browser, that request gets POSTed again, and your database got tainted. Same for PATCH, PUT and DELETE requests.
You can redirect the user to a GET path if the non-GET request succeeds, or to a 400 page if the non-GET request fails.
I'm trying to create a cancel button in a rails view, which links to a PATCH/update method. I want to pass a query string parameter -- update_action: "cancel" -- so the update method knows that this is a cancel action and can process it accordingly. This is the link_to method for the cancel button:
<%= link_to "Cancel", {controller: "/orders", action: "update", id: order.id, update_action: "cancel" }, method: "patch" %>
However, when I do this, I get a routing error:
Unable to find route for [GET] order/update/id?update_action=cancel
For some reason it is trying to route to a GET request instead of a PATCH request.
Now, when I remove the query string parameter from the link_to method, i.e.
<%= link_to "Cancel", {controller: "/orders", action: "update", id: order.id }, method: "patch" %>
It correctly routes to PATCH orders/id,
Why is my link_to method not routing to a PATCH request when I include the query string parameter?
Note, by routes.rb file contains:
resources :orders
You can give this a try, though I doubt it will work any better:
<%= link_to "Cancel", order_path(id: order.id, update_action: "cancel"), method: "patch" %>
Routing in rails is implemented using RESTful architecture. Hence you can send query string params with a GET request. A PUT request typically does not contain query params. Those params are submitted in the request body (like using a form) as seen in the example below from guides
class ClientsController < ApplicationController
# This action uses query string parameters because it gets run
# by an HTTP GET request, but this does not make any difference
# to the way in which the parameters are accessed. The URL for
# this action would look like this in order to list activated
# clients: /clients?status=activated
def index
if params[:status] == "activated"
#clients = Client.activated
else
#clients = Client.inactivated
end
end
# This action uses POST parameters. They are most likely coming
# from an HTML form which the user has submitted. The URL for
# this RESTful request will be "/clients", and the data will be
# sent as part of the request body.
def create
#client = Client.new(params[:client])
if #client.save
redirect_to #client
else
# This line overrides the default rendering behavior, which
# would have been to render the "create" view.
render "new"
end
end
end
If you only want a 'Cancel' button, you can use the same path as a GET request. Your params {update_action:"cancel"} will be available in the controller. It also makes sense as you are trying to GET/fetch a different page.
A PUT/PATCH request is used to update/create data in models, while POST is to create.
A GET request will fetch pages, or back to previous pages (like in cases of 'cancel').
I have a Rails app that is supposed to send a POST request, but for some reason is sending a GET.
View:
<% if #competition.users.exclude?(#user) %>
<%= link_to 'Attend Competition', attend_competition_path(#competition.id), :method => :post %>
<% else %>
<%= link_to 'Withdraw', withdraw_competition_path(#competition.id), :method => :post %>
<% end %>
Controller:
def attend
p current_user.daily
#competition = Competition.find(params[:id])
if #competition.users.include?(current_user)
flash[:error] = "You're already attending this competition."
elsif current_user.daily == []
flash[:error] = "You must have a working device to compete."
else
current_user.competitions << #competition
flash[:success] = "Attending competition!"
end
redirect_to #competition
end
def withdraw
p "WITHDRAWING"
#competition = Competition.find(params[:id])
p #competition
attendee = Attendee.find_by_user_id_and_competition_id(current_user.id, #competition.id)
if attendee.blank?
flash[:error] = "No current attendees"
else
attendee.delete
flash[:success] = 'You are no longer attending this competition.'
end
p attendee
redirect_to #competition
end
Routes:
resources :competitions do
post 'attend', on: :member
end
resources :competitions do
member do
post 'withdraw'
end
end
So I click on the button and go to the page, but get an error that there is no route for a GET request. There shouldn't be a route for get requests, but it should be sending a post.
ActionController::RoutingError (No route matches [GET] "/competitions/1/withdraw")
One thing you can do is to run:
rake routes
That will show you all your available routes and their methods. I believe since you are doing a post to a method other then create that it is not understanding what you are trying to do. I am looking to see if I can find the proper way to do this, but I did find that the Rails documentation says:
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?.
So you may need to check for a post in your controller action. I looked for an example of how to do this but couldn't find anything.
Looking at your routes, it should work the way you have it. One other thing to try is to use "put" instead of "post."
One other option that you may want to consider is to make it a form and style the button like a link if that is the look you are going for.
Mike Riley