Using the rails button_to helper I'm trying to run the update method in a controller. I need to set the ID of the object being updated manually. The code I have I think should be right, but rails keeps trying to put the ID as part of a route.
in the view:
button_to ">", :controller=>'people', :action=>'update', 'person'=>{:team=>team_leader.team}, :id=>currently_viewing_person
in the controller:
def update
#person = Person.find(params[:id])
#...rest of method
end
The controller update method is never executed. The error on the web browser is:
Unknown action
No action responded to 3. Actions: create, index, new, search, show, and update
'3' was the value of currently_viewing_person
What's the correct way to pass :id so update can extract from params[:id]
button_to uses POST by default. For update you need a PUT, so pass in the method along with the other parameters:
button_to ">",
{ :controller=>'people', :action=>'update',
'person'=>{:team=>team_leader.team},
:id=>currently_viewing_person },
:method => :put
Note that the method has to be passed in as a separate hash
Here's to reading the documentation again, and understanding that in a REST architecture, update is sent via PUT, not POST. The correct view code is:
button_to ">", {:controller=>'people', :action=>'update', 'person'=>{:team=>team_leader.team}, :id=>currently_viewing_person}, :method => :put
Oddly, if I view source on this page the form created by button_to shows POST being used:
<form method="post" ...
But the rails log confirms that PUT was indeed used:
Processing PeopleController#update (for 127.0.0.1 at 2010-07-15 00:10:09) [PUT]
Related
I would like to use a drop action in the friendships controller to drop requests of friendship, and I am struggling to understand how to create a working form and working routes.
I added the following route in config/routes.rb
resources :friendships, only: [:create, :destroy] do
member do
post :drop
end
end
This would generate the named route drop_friendship_path(id).
My question is now how to create a working form, that is what parameters am I necessarily required to use with form_for or form_tag.
Since in view I would iterate on #users requesting a friendship, I would not know the id of the request to delete, so I cannot use the above named route. Which one of the following is correct?
<%= form_for(current_user.friendship_request.find_by(requester_id: user.id), url: { action: drop }) %>
<%= form_tag({controller: "friendships_controller", action: "drop"}) do %>
I struggled to find documentation on parameters to use with form_for and form_tag. The api documentation says that the :url
argument for form_for may be represented in the same way as values passed to url_for or link_to. So for example you may use a named route directly. Documentation on url_for or link_to however does not add anything else.
I found only examples, not an exhaustive documentation, in the form helpers section of guides.rubyonrails.org for form_for and form_tag, so I realized that url for form_for can have a hash of subparameters (however only action is reported) , and that the controller and action parameters can be passed to form_tag.
What is the complete list of parameters for the url hash in the form_for helper?
What is the relative list of parameters for the form_tag helper?
Which ones are required in my form?
If, instead of specifying controller and action, I used inside form_for or form_tag:
url: drop_friendship_path(#friendship_request)
and defined #friendship_request in the drop action, would that work?
A better way is to use button_to or link_to helpers for your purpose. button_to generates a form. link_to generates a link, but can also send post request with {method: :post} option.
Why do you think you can't use the drop_friendship_path(id) helper method? You can:
<% request_id = current_user.friendship_request.find_by(requester_id: user.id) %>
<%= button_to "Drop", drop_friendship_path(request_id) %>
<!-- or -->
<%= link_to "Drop", drop_friendship_path(request_id), method: :post %>
Why don't you use the existing destroy action to delete friendships instead of drop ?
And also, sending a separate query for each user to get a friendship record is not a good thing. You should think of how you can avoid this. There are many solutions, but it is not the subject of the question.
New to rails (programming as a whole), and I'm a little confused about routing.
I have a form in my view that takes someone's email, and then emails them once they hit submit. It works, but after I hit submit I'm being redirected to the view for the method I'm calling in order to mail the form. I don't want to be redirected, I want to stay on the same page. I have attempted using POST and PUT, but both redirect me. Am I using my controller incorrectly?
My controller has this method:
def mail
recipient_email = params[:email]
itinerary_body = params[:body]
x = ItineraryMailer.itinerary("#{recipient_email}", "#{itinerary_body}")
x.deliver
end
And here is the form from my view:
<%= form_tag({controller: "bookings", action: "mail"}, method: "post") do %>
<%= text_field_tag(:email) %>
<%= text_field_tag(:body) %>
<%= submit_tag("Email Me!") %>
My route:
match '/bookings', to: 'bookings#mail', via: 'post'
Thank you!
Since you don't have a redirect_to in your mail action Rails isn't redirecting you anywhere. Instead, it's just trying to render that action's view directly. However, I'm guessing that isn't the view you want rendered.
So, instead of trying to prevent a redirection (which isn't happening anyway) I would suggest that you take the opposite approach: use a redirection to get to the correct view. At the end of your mail action do this:
redirect_to action: :original_action_name
Where :original_action_name is the name of the action that gave you the view you want.
You could also use the render 'action' suggested in a comment, but that can cause problems in some cases where the current action may not have loaded or set up everything needed by the view you want to have rendered. Of course, you could just do that loading/setup in the current action but then you are doing the same thing in two places which isn't DRY.
all, I'm trying to get a custom action to work with a put method: in the
in _post.html.erb i have a link_to statement:
<%= link_to 'End now', post, :method => :put, :action => endnow %>
routes.rb contains:
resources :posts do
member do
put :endnow
end
and posts_controller.rb looks like:
class PostsController < ApplicationController
helper_method :endnow
[.. code for create, edit, destroy, etc ..]
def endnow
puts params
end
end
rake routes's relevant line looks like:
endnow_post PUT /posts/:id/endnow(.:format) posts#endnow
However, the action endnow helper doesn't run when clicking on this link.
Strangely, it does run with an index action (which i can tell from the puts command.
Of course, eventually the code for endnow will update #post, but for now, it just doesn't run properly.
Maybe i'm going about this the wrong way - all I'm trying to achieve is to update #post upon clicking the link to that post, and before showing it.
Any ideas / Alternatives?
Why not use the route helper method provided to you? Change your link to
<%= link_to 'End now', endnow_post_path(#post), method: :put %>
Things you're doing wrong:
If you want to specify the :action, use the Symbol for the action (you're missing a colon). :action => endnow should be action: :endnow
I will assume you have a #post instance variable you're passing from your controller to your action. You should be using that instead of post (unless you do in fact have a local post variable you're omitting from your code)
You are using endnow as an action; you should remove the helper_method :endnow line in your controller because it's not something you want to/should be accessing from your view.
This can all be avoided by using the route helper (for endnow_post you'd append _path to get the local route path: endnow_post_path), and pass in your #post as an argument.
Because you're trying to do a PUT request, you must make sure you have something like jquery-ujs included in your asset pipeline to convert these links to form submissions behind the scenes; browsers don't support PUT via the click of a link on their own.
As for why you're getting the template error when you get your link_to working, Rails is telling you that you need to create a app/views/posts/endnow.html.erb file. Your action has only puts params which does not terminate execution, leaving Rails to assume you still are trying to render some endnow.html.erb template.
Are there other ways to do what you're trying to do (change a single attribute of a specific model)? Sure. Are there better ways? That's pretty subjective; it may not be the most RESTful way, but it's arguably easier to deal with (if for example there are very specific authorization rules to check before updating the attribute you are modifying in endnow. Does the way you've started fleshing out work? Absolutely.
Finally, as a bump in the right direction, after you fix your link_to and remove the the helper_method as I have described above, your endnow action might look like this:
def endnow
post = Post.find!(params[:id])
post.some_attribute_here = some_new_value_here
post.save
redirect_to :root and return # <- this line sets a redirect back to your homepage and terminates execution, telling rails to do the redirect and **not** to render some endnow.html.erb file
end
I want to pass some parameters with link_to method to create method, so that the form will shown prefilled to a user.
I wrote this code to pass the parameters,
<%= link_to "Buy", new_transaction_url(:friend_id => #friend.id, :t_type => 2) %>
And in transactions_controller's new method, I have:
#transaction = Transaction.new
#transaction.t_type = params[:t_type]
It didn't work as well.
That would be great if you can help me.
Thanks.
Try change params[:t_type] to params[:transaction][:t_type].
Usually new_transaction_url would call the #new action in your controller, not the #create action. Watch your log file while you do it to see exactly what controller action is being called and what parameters are being passed.
I'm trying to create a simple search form in Rails, but I think I'm missing something.
I have a named route for search:
map.search ":first_name/:last_name", :controller => "home", :action => "search"
I'm trying to use that in my search form:
<% form_tag(search_path, :method => 'get') do %>
<%= text_field_tag(:first_name) %>
<%= text_field_tag(:last_name) %>
<%= submit_tag("Search") %>
<% end %>
But when I load up the search form I get an ActionController::RoutingError:
search_url failed to generate from {:action=>"search", :controller=>"home"} - you may have ambiguous routes, or you may need to supply additional parameters for this route. content_url has the following required parameters: [:first_name, :last_name] - are they all satisfied?
What am I missing? I thought the fields defined in my form would be automatically linked up with my route parameters. :-/
Update:
I understand that search_path is generated before the form is displayed now, so it can't be updated. Obvious in hindsight!
I changed my routes:
map.search 'search', :controller => "home", :action => "search"
map.name ':first_name/:last_name', :controller => "home", :action => "name"
And now the search action just does:
def search
redirect_to name_path(params)
end
It all works a treat! The main goal here was getting that URL from the name named route as result of doing a search. Thanks guys!
form_for generates form and it has to have specified all parameters that are needed to create search_path, so it should look like:
<% form_tag(search_path, :firstname => 'some_text', :lastname => 'some_text', :method => 'get') do %>
or at least something like this. HTML tag form has parameter action='/some/url' and that's why you have to specify all parameters for search_path. But the above example won't work as you expected.
So what you can do?
Create empty form that has action='/' and with js replace it with content of your input text fields before submitting.
Create another route, on example /search that recives parameters from submit and then redirects to correct path.
Probably there is also some better ways to do it ;)
First, search_path is actually a method, which takes a hash of options. It is this method which should receive :first_name and :last_name.
Second, a browser can only submit form parameters as the body of a POST request, or as query string parameters (for any kind of request method). So there's unfortunately no way a browser's native submit function can generate that kind of URL.
Another way of thinking of it: What you're doing here is filling the form tag's action attribute with an URL. Rails needs a complete URL as you're building the form. So all parameters in your route need to be specified when the form helper is called, rather than at the next POST request.
So unfortunately, what you're trying to do is not possible in a normal Rails application.
(If you really want to, you might be able to pull it off by writing your own form helpers and a bit of Javascript to replace the browser's native submit function. The Javascript would then construct that URL based on the form fields. I'd argue against it, though.)