Rails has_many through association delete path - ruby-on-rails

I have a place model and a user model and a user_place model, user_place belongs to user and place both. Traditional has_many through association.
I have a page where you can view the users associated with a place. My routes look like:
resources :places do
resources :user_places
end
which generates these routes:
place_user_places GET /places/:place_id/user_places(.:format) user_places#index
POST /places/:place_id/user_places(.:format) user_places#create
new_place_user_place GET /places/:place_id/user_places/new(.:format) user_places#new
edit_place_user_place GET /places/:place_id/user_places/:id/edit(.:format) user_places#edit
place_user_place GET /places/:place_id/user_places/:id(.:format) user_places#show
PATCH /places/:place_id/user_places/:id(.:format) user_places#update
PUT /places/:place_id/user_places/:id(.:format) user_places#update
DELETE /places/:place_id/user_places/:id(.:format)
I don't love this but I'm ok with it for now.
But whenever I try to delete a user_place I have all sorts of issues.
<%= link_to "delete", place_user_place_url(place_id: #user_place.place_id, id: #user_place.id), method: 'delete' %>
No route matches {:action=>"show", :controller=>"user_places", :id=>nil, :place_id=>2}, possible unmatched constraints: [:id]
I had this working previously with slightly different routes and an actual form:
resources :places do
resources :user_places, as: 'user', only: %i[index create new]
delete 'remove_user', to: 'user_places#remove_user'
end
<% if user != current_user %>
<%= form_with model: #user_place, url: place_remove_user_path(#place.id), method: 'delete' do |form| %>
<%= form.hidden_field :user_id, value: user.id %>
<%= form.hidden_field :place_id, value: #place.id %>
<%= form.submit "delete" %>
<% end %>
<% end %>
But this feels hacky, I don't think I should need a specific form, and this was leading the form to be submitted with javascript which I don't want.

What might be a solution is to use shallow nesting in the routes (shallow: true).
resources :places do
resources :user_places, shallow: true
end
Make sure to run rails routes again. The delete method of a user_place will no longer be nested.
You can then simply delete the user_place passing a single variable (an instance of a user place, #user_place). There is no need to set the id (place_id or id) as Rails is smart enough to handle that. Just passing an instance variable is enough for the delete method to find the corresponding record.
<%= link_to "delete", user_place_url(#user_place), method: 'delete' %>

Related

How to override function new so I can send parameter

I have model Product with has_may :benefits, now in link_to for new benefit I don't know how to send ID of product so I can go with
Product.find(params[:id]).benefits.new(...)
Normal new method is
<%= link_to t('add_new_benefit'), new_admin_benefit_path %>
I want to send #product object so I can get id from it.
I wanna send it like this
<%= link_to t('add_new_benefit'), new_admin_benefit_path(#product) %>
routes.rb
...
namespace :admin do
root "action_logs#index"
get "toolkit", to: "toolkit#index"
resources :admins
resources :products
...
resources :benefits
end
I believe you just want to pass id as a param. Eg:
<%= link_to t('add_new_benefit'), new_admin_benefit_path(product_id: #product.id) %>
Many examples here

How to Write link_to for acts_as_votable nested resources?

I am trying to add voting to my site. I have improvements that are created and displayed inside of the projects show page. I'm trying to allow users to vote on improvements but I am getting an error that I think is related to how I'm linking the like button.
in my routes.rb file:
resources :projects do
resources :improvements do
member do
put "like" => "improvements#upvote"
put "unlike" => "improvements#downvote"
end
end
end
In my view:
<%= link_to like_improvement_path(improvement), class: "like", method: :put do %>
Rails recommended me to write:
<%= link_to project_like_improvement_path(improvement), class: "like", method: :put do %>
But this doesn't work. So I tried doing this in my routes.rb:
resources :projects do
resources :improvements
end
resources :improvements do
member do
put "like" => "improvements#upvote"
put "unlike" => "improvements#downvote"
end
end
Using the original link_to, the voting works, but clicking on the vote button takes me to the improvements show page. I want to stay on the projects page.
If:
<%= link_to like_improvement_path(improvement), class: "like", method: :put do %>
Works then in the improvements controller's (upvote?) action simply do a:
redirect_to projects_path
At the end of whatever else you do model wise.
Change "projects_path" to the correct route for the page.
I had the same problem. The solution with your original routes.rb:
<%= link_to like_project_improvement_path(improvement.project, improvement), class: "like", method: :put do %>
You can write a redirect_to inside the upvote and downvote methods in the improvements controller.

How to search all nested resources without the parent resource?

My app's got Listings nested within Categories.
I can search all the listings when I'm in a particular category with this form:
<%= form_tag category_listings_path(#category), method: :get do %>
<p>
<%= text_field_tag :search, params[:search] %>
<%= submit_tag 'Search', name: nil %>
</p>
<% end %>
As you can see, I must make a get request to the category_listings_path and pass in the current Category.
However, this method fails when I want to put the search bar on a page where no Category exists!
How can I search for all Listings without needing to pass in a Category?
Based on what you wrote, I'm guessing your routes look something like:
resources :categories do
resources :listings
end
This means that all of your routes for listings require a category id. If you want a path for all listings, regardless of category, add:
resources :listings, only: [:index]
to your routes. Then you can have a form that searches to listings_path (which is the path that above route creates) and you don't need a category id.

acts_as_votable gem routes error

i'm new to rails and trying to get upvotes for questions working using the acts_as_votable gem. I am getting the following error telling me i have no route matches:
No route matches [GET] "/questions/1/like"
Here is my upvote method in my questions_controller.rb:
def upvote
#question = Question.find params[:question_id]
#question.liked_by current_user
redirect_to #questions
end
My routes.rb file:
resources :comments do
resources :questions
member do
put "like", to: "questions#upvote"
end
end
and my upvote button:
<%= link_to "Upvote", like_question_path(#comment, #question, method: :put) %>
Thanks for the help!
The path name like_question_path is incorrect. It should contain at least "comment", something like "like_comment_question_path". Please consult your $rake routes for accurate name.
By the way, is there any reason you need to use put? In my opinion this action is not to change existing data but add a new one, so 'POST' should be more appropriate.
Try this:
routes.rb
resources :comments do
resources :questions do
put "like", to: "questions#upvote"
end
end
Upvote button:
<%= link_to "Upvote", comment_question_like_path(#comment, #question), method: :put %>
You need the correct path, and also the method for link_to to use goes after the second parameter.
The method option should be outside of the named route, like this:
<%= link_to "Upvote", like_question_path(#comment, #question), method: :put %>
Also, what #Billy Chan said.

Route to controller action

I created an form_tag form:
<%= form_tag(set_image_dokumente_path) do %>
<%= text_field_tag :shit,'', data: {autocomplete_source: search2_patients_path}, :class => "shit" %>
<% end %>
I try to route to set_image action of dokumente controller, but i get the error:
undefined local variable or method `set_image_dokumente_path' for #<#<Class:0x711ff60>:0x762d578>
By default my form_tag goes to dokumente controller index action!
My routes:
resources :images
get "dokumente/index"
post "dokumente/index"
match 'patients/list' => 'patients#list'
resources :patients do
collection do
get :search2
end
end
How do i have to change it?
You can add the as: parameter to you route in order to create a named path.
For example:
post "dokumente/index", as: 'set_image_dokumente'
or similar, I'm not sure what you are trying to achieve, but I hope you get the idea :)
More info:
http://guides.rubyonrails.org/routing.html#generating-paths-and-urls-from-code

Resources