Ruby on Rails Convert Button To Link - ruby-on-rails

I have this button in a view:
<%= button_to 'Add Review', {controller: 'reviews', action: 'new', id: booking.showing.film.id } %>
Which then sends the user to the new review path and uses the film's id to enable the new review form to know what film is being reviewed. This is done through the routes:
post 'reviews/new/:id', to: 'reviews#new'
But the button does not look very nice so I want a link_to. I have tried this:
<%= link_to 'Add Review', {controller: 'reviews', action: 'new', id: booking.showing.film.id } %>
But through my errors routing:
match '*a', to: 'errors#routing', via: [:get, :post]
It will send the user back to the index page and display the message: No such path as 'reviews/new/6'
How can I make a link that does exactly the same as the button?

Your route requires a POST request, which the button makes, but link_to makes an <a> element, which will make a GET request. You can't make an <a> submit a POST. I suggest you use the button and restyle it with CSS to look like a link.

You can use the :method option to set http verb (e.g. :post) in link_to (see http://api.rubyonrails.org/classes/ActionView/Helpers/UrlHelper.html#method-i-link_to).
However, you should consider changing your route since the reviews#new action renders the new review form. Use the POST request when creating or updating data.

Related

form_for and form_tag parameters for custom action

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.

How to get the route by helper name?

I have the following set of routes which point to the same view:
get 'mypath', to: 'home#mypath', as: 'mypath'
get 'mypath-v2', to: 'home#mypath', as: 'mypath_v2'
get 'mypath-v3', to: 'home#mypath', as: 'mypath_v3'
How can I check if I am using one route or the other inside the view?
For example if I want to get mypath-v2 or mypath_v2, how would I do it?
Well, as for me it is better to do such things using params. You can define your routes like this:
get "mypath/:version", :as => "mypath"
In this case you will be able to use params[:version] to clarify current path.
You would call it by appending _path or _url
For instance here is an example in a link:
<%= link_to 'Link to mypath-v2 page', mypath_v2_path %>
OR
<%= link_to 'Link to mypath-v2 page', mypath_v2_url %>
To compare them you can look at the request object. When you call request.path or request.fullpath it will bring in the actual address request path of the link.
So...
<%= if request.path.eql?('mypath-v2') ? "Used It" : "Other Route" %>

No route matches POST confusion

I am very unfamiliar with routing and the entire back-end of Rails in general. I am attempting to have a click on "edit cart" lead to the edit page, I have the edit_cart_path and corresponding view- but when I click the edit cart button, I get
Routing Error
No route matches [POST] "/carts/21/edit"
I have resources :carts in routes.rb, I have get "/carts/:id/edit" => "carts#edit" as well. Have tried a couple other methods including "via: get". Why is it insisting on POST, and how to solve this?
I'm guessing you're doing something like this, in your view:
button_to(edit_cart_path(#cart))
When using a button_to helper, the default HTTP method will be POST.
You'll have to do explicitly define the HTTP method you want to execute:
button_to(edit_cart_path(#cart), method: :get)
I would encourage you to use the link_to helper instead, and add any button effect using CSS:
link_to(edit_cart_path(#cart), class: 'btn')
From the Rails 4 documentation:
button_to(name, options = {}, html_options = {})
The options hash accepts the same options as url_for.
There are a few special html_options:
:method - Symbol of HTTP verb. Supported verbs are :post, :get,
:delete and :put. By default it will be :post.

Rails 3 edit_path method not working

sorry if this is a dumb Q, this is my first Rails3 project...
For some reason, this <%= link_to 'edit', edit_geofence_path(geofence) %>
renders as edit (my geofence's id is 2).
And <%= link_to 'delete', {:action=>'destroy', :id=>geofence}, :confirm=>"You sure?", :method=> :delete %>
renders as delete,
which might be fine, but clicking the link generates this in the logs Started GET "/geofence?id=2". So, not DELETE, just GET.
My routes.rb file is just resource :geofence.
On a related note, for some reason the default action for a geofence is "show". So /geofence/ DOES NOT call the index method, it calls the show method. I think that also must be wrong.
I'm done cursing at this app for now, I'm going to take a day to cool off and hopefully get this SIMPLE SCAFFOLD working tomorrow night... Help me, stackoverflow! You're my only hope!
<%= link_to 'delete', {:action=>'destroy', :id=>geofence}, :confirm=>"You sure?", :method=> :delete %>
should be:
<%= link_to 'delete', {:action=>'destroy', :id=>geofence}, :confirm=>"You sure?", :method=> :delete, :remote => true %>
Without :remote => true, the click isn't handled by javascript.
And in your routes.rb file, you should have that defined as:
resources :geofence
Setting it as resource implies that there is only one, and is causing a lot of your weird behavior.
As a side note, to complete ctide answer I would suggest you to use the plural form of your controllers name as a convention. It will sound more natural to put:
resources :geofences
inside your routes.rb file.
Here is a previous StackOverflow question, about using the plural form as a convention for controllers.
When you use resource :geofence in your routes file you are telling your application that there is only one geofence resource, and that it is not a collection. You will get show, update, create, new, but not index - and the id value will not be used because there is only one resource. (The show action here will have the path /geofence
If you use resources :geofences (notice the pluralization) then you've defined a collection of resources, /geofences will now give you the index action and your url helpers will work correctly with the show action rendering /geofences/3.
Hope this helps you understand why the plural form is necessary for this sort of resource :)

Ruby on Rails: link-to using post method but parameters are in the URL

I'm using
link_to 'My link', path(:arg1 => session[:arg1], :arg2 => session[:arg2],:arg3 => anyobject.id), :method => :post
but the HTML link being generated includes (arg1,arg2,arg3) as URL query parameters.
How can remove them? Did I miss something in the documentation?
A link_to will always put the arguments into the query string as it is creating a get-style HTML link - even if you put :method => :post that just appends an extra ("special") argument _method.
What I think you really want is a button_to link - which will make it into a sort of form-post. It works the same, but it says button_to instead (for example, button_to 'My link', path(:params => :go_here). The downside is that it will look like a button. But you can give it a CSS class (eg "unbutton") and then change the styling on that CSS class to make it not look like a button.
Alternatively, if what you really want is actually to have no params passed to the controller at all... then just don't include them when making your link (for example, link_to "My link" path - there's no need for :post if you don't want to post any params).
Finally, if what you want is for the params to become a part of the URL (for example, stuff/[param_1]/more_stuff/[param_2], etc.) then you need to update your routes to include these parameters as options. Have a look at the routing section of the rdoc for how to do that.
You can use below code, which rails.js need data-method to switch to post mode in Ajax.
<%= link_to '<button id="print" type="submit" class="btn">Print</button>'.html_safe, { controller: :lots, id: #lot.containername, action: "print_#{print_template}", remote: true }, {'data-method' => :post} %>

Resources