Route using dot rather than / in rails DELETE method - ruby-on-rails

The delete button I have in my rails app returns the following error :
No route matches [DELETE] "/requests.3"
I'm not sure why.
Here is the button link in the request view (using bootstrap 3) :
<%= link_to '<i class="glyphicon glyphicon-remove"></i>'.html_safe,
requests_path(request), method: :delete,
data: { confirm: 'Are you sure?' }, class: 'btn btn-danger' %>
and in routes I have :
delete 'requests/:id' => 'requests#destroy'
and in the controller I have
def destroy
#request = Request.find(params[:id])
#request.destroy
redirect_to action: 'index', status: 303
end
Any help would be appreciated.
Thank you.

The solution I figured to work was to manually specify the path in the <%= link_to tag
<%= link_to '<i class="glyphicon glyphicon-remove"></i>'.html_safe,
"/requests/#{request.id}/destroy", method: :delete,
data: { confirm: 'Are you sure?' }, class: 'btn btn-danger' %>
and that seemed to work.

Related

Ruby Rails delete confirmation not popping up before destroy

I am trying to delete a record from my database using Rails destroy action and button_to, however, the confirmation does not pop up and the app simply deletes the record without confirmation. I've tried multiple approaches:
<%= button_to 'Delete', post_path, :method => :delete, :confirm => 'Are you sure you want to delete this item?' %>
<%= button_to 'Delete', post_path, method: :delete, data: { confirm: 'Are you sure?' } %>
<%= button_to 'Delete',post_path, :method => :delete, data: { confirm: 'Are you sure you want to delete this item?'}
<%= button_to 'Delete', post_path, {method: :delete}, {confirm: 'Are you sure?'} %>
Neither shows a confirmation module.
I was able to get this to work by following this here.
https://dev.to/software_writer/how-to-show-a-delete-confirmation-dialog-in-rails-using-stimulus-17i
Basically what you want to do is create a Stimulus js file in your app/javascript/controllers. In your case it would be posts_controller.js. Then put the following code in posts_controller.js.
import { Controller } from "#hotwired/stimulus"
export default class extends Controller {
// method for alerting before deleting posts
delete(event) {
let confirmed = confirm("Are you sure?");
if(!confirmed) {
event.preventDefault();
}
}
}
When you create the button to delete your post, have the parent div container have the data-controller="posts" attribute. Then set the action for the button_to to your method in your posts_controller.js. It should look something like this.
<div id="postDeleteLink" data-controller="posts">
<%= button_to "Delete this post", #post, method: :delete, data: { action: "click->posts#delete" } %>
</div>

ruby-on-rails - custom method and link_to

I have a program with users and projects (many to many relation). I would like to create my own methods: to delete all projects from specific user and to delete specific project from specific user, but I can't handle that. There is (quiet big) possibility I don't understand routes.
Below I insert code to delete all project from specific user.
In my user_controller.rb I have:
def delete_projects_from_user
#user.projects.delete_all
end
In show.html.erb link_to:
<%= link_to 'Delete all projects', #user, method: :delete_projects_from_user, data: { confirm: 'Are you sure?' } %>
And in routes I tried among others this two option:
resources :users do
get 'delete_projects_from_user', on: :member
end
or
post '/users/:id', to: 'users#delete_projects_from_user', as: :delete_projects_from_user
First option trows: "No route matches [POST] "/users/(id)"
Second option just do nothing.
I will be grateful for prompt.
Basic format:
<%= link_to 'DISPLAY TEXT', YOUR_ROUTE_path(#object), method:
:HTTP_METHOD, data: { Additional html params } %>
Here is the solution:
<%= link_to 'Remove All Projects', delete_projects_from_user_path(#user), method: :post, data: { confirm: 'Are you sure?' } %>
Then in your method:
def delete_projects_from_user
user = user.find(params[:id])
user.projects.delete_all
redirect_to :back #if nothing to render
end
I'm sure this may help you.
For this
def delete_projects_from_user
#user.projects.delete_all
end
You better user .destroy_all to make sure this object and all of it's associated items are destroyed as well
.delete_all only delete the object and it leaves the associated entries on the DB
and As for this:
<%= link_to 'Delete all projects', #user, method: :delete_projects_from_user, data: { confirm: 'Are you sure?' } %>
In your route you defined your route as post so it should be
method: :post
to be like this
<%= link_to 'Delete all projects', #user, method: :post, data: { confirm: 'Are you sure?' } %>
And here you haven't added the route correctly, it should be like this
<%= link_to 'Delete all projects', YOUR_ROUTE_path(#user), method: :post, data: { confirm: 'Are you sure?' } %>
While it's recommended to define this route like this
delete '/users/:id', to: 'users#delete_projects_from_user', as: :delete_projects_from_user
As for the 2nd option, you can use collection as well
resources :users do
collection do
delete 'user/:id', to: 'users#delete_projects_from_user', as: :delete_projects_from_user
end
end
and modify the link to be
<%= link_to 'Delete all projects', delete_projects_from_user(#user), method: :delete, data: { confirm: 'Are you sure?' } %>
Both options are fine, and the 2nd one with delete is the recommended one

Ruby on Rails add confirmation to link_to

I'm building a Ruby on Rails application and I have generated some scaffold.
I want to add a confirmation box (like the one that pops up when you delete an element) to a custom link I created.
The syntax for the element deletion is the following:
<td><%= link_to 'Destroy', user, method: :delete, data: { confirm: 'Are you sure?' } %></td>
This is my custom link:
<td><%= link_to 'set done', :controller => 'users', :action => 'set_donation_done', :user => user, data: { confirm: 'Are you sure?' } %><td>
The problem is that the confirmation box on my custom link does not appear. If I inspect the element I see the following html code:
set done
What am I doing wrong?
Try with this:
<%= link_to 'set done', { controller: 'users', action: 'set_donation_done' }, user: user, data: { confirm: 'Are you sure?' } %>
Remember:
link_to(body, url_hash, html_hash)
http://apidock.com/rails/ActionView/Helpers/UrlHelper/link_to
Found the solution:
<td><%= link_to 'set done', {:controller => 'users', :action => 'set_donation_done', :user => user}, data: { confirm: 'Are you sure?'} %><td>
Whit this formula I have my user data in params and I can see the confirmation box!
You don't need the controller action hash. Simply show when the HTML hash starts like so:
<td><%= link_to 'Destroy', user, method: :delete,{ data: { confirm: 'Are you sure?' }} %></td>

Render output of multiple expressions in one ERB block

I have a helper that looks like this:
if current_user.find_voted_items(vote_scope: :inspired).include?(post)
link_to vote_inspired_post_path(post, vote_scope: :inspired), method: :post, data: { confirm: 'Are you sure this post Inspires you?' }, class: "btn btn-default" do
"<i class='fa fa-lightbulb-o'></i> <br />Inspired".html_safe
end
link_to vote_happy_post_path(post, vote_scope: :happy), method: :post, data: { confirm: 'Are you sure this post makes you happy?' }, class: "btn btn-success" do
"<i class='fa fa-smile-o'></i> <br />Happy".html_safe
end
link_to vote_disappointed_post_path(post, vote_scope: :disappointed), method: :post, data: { confirm: 'Are you sure this post disappointed you?' }, class: "btn btn-info" do
"<i class='fa fa-meh-o'></i> <br />Disappointed".html_safe
end
link_to vote_upset_post_path(post, vote_scope: :upset), method: :post, data: { confirm: 'Are you sure this post upsets you?' }, class: "btn btn-inverse" do
"<i class='fa fa-frown-o'></i> <br />Upset".html_safe
end
end
I need all the links and their nested <i> tags to be rendered - but for some reason, this version is just rendering the last line.
All of that is inside a method called show_vote_buttons(post), that is being called like this in the view: <%= show_vote_buttons(#post) %>
What's the best way to tackle this?
Basically, the reason behind this is that <%= %> renders the output of show_vote_buttons method. This method doesn't explicitly return anything, so the last evaluated expression is returned, in your case, the last link_to output.
In a general case, if you have not used a helper method and just pasted it's body instead with multiple link_to calls, you would get the same behavior. The reason is similar: <%= %> does not render each link_to, it executes code inside <%= %> and then outputs the result of last evaluated expression.
I see two different approaches to change the output:
Helper method: concatenate the output of all evaluated expressions and print as one string:
1.1 using << and parenthesis () around each link_to;
1.2 creating a string with double quotes " and interpolating each link_to output with #{} in it;
1.3 using concat;
Partial views: build a separate view from your existing helper method and use <%= %> to output each link_to.
P.S. After testing all four methods I've come to a conclusion (here comes a personal opinion) that the second method is more preferable, at least because it keeps rendering in the views and avoids concatenation that can look messy. Similar approach is used, for example, in the Devise gem, where all shared links are located in the app/views/devise/shared/_links.html.erb partial.
but for some reason, this version is just rendering the last line.
That reason is because in Ruby, if a method doesn't have an explicit return, then the returned value of a method is the value of the last line that got executed before a method exited. If you want to return multiple values from a method, use the return keyword and comma-separate your values.
#will return an array [1,2,3]
def some_method
return 1,2,3
end
Also, I do agree with the other answers that your code should be more DRY, but I was simply trying to clarify your original question.
Have a try with this code
if current_user.find_voted_items(vote_scope: :inspired).include?(post)
concat(link_to vote_inspired_post_path(post, vote_scope: :inspired), method: :post, data: { confirm: 'Are you sure this post Inspires you?' }, class: "btn btn-default" do
safe_concat(content_tag(:i, "Inspired", calss: "fa fa-lightbulb-o"))
end)
concat(link_to vote_happy_post_path(post, vote_scope: :happy), method: :post, data: { confirm: 'Are you sure this post makes you happy?' }, class: "btn btn-success" do
safe_concat(content_tag(:i, "Happy", calss: "fa fa-smile-o"))
end)
concat(link_to vote_disappointed_post_path(post, vote_scope: :disappointed), method: :post, data: { confirm: 'Are you sure this post disappointed you?' }, class: "btn btn-info" do
safe_concat(content_tag(:i, "Disappointed", calss: "fa fa-meh-o"))
end)
concat(link_to vote_upset_post_path(post, vote_scope: :upset), method: :post, data: { confirm: 'Are you sure this post upsets you?' }, class: "btn btn-inverse" do
safe_concat(content_tag(:i, "Upset", calss: "fa fa-frown-o"))
end)
end
Note: Didn't tested it.
The reason is perfectly explained by #suslov around this answer. Metaprogramming might keep code DRY:
DATA = {
inspired: { ico: 'fa-lightbulb-o',
msg: 'Are you sure this post Inspires you?',
btn: 'btn-default' },
happy: { ico: 'fa-smile-o',
msg: 'Are you sure this post makes you happy?',
btn: 'btn-success' },
... }
if current_user.find_voted_items(vote_scope: :inspired).include?(post)
DATA.map do |k, v|
instance_eval %Q{
link_to vote_#{k}_post_path(post, vote_scope: :#{k}),
method: :post,
data: { confirm: #{v[:msg]} },
class: "btn #{v[:btn]}" do
"<i class='fa #{v[:ico]'></i> <br />#{k.capitalize}".html_safe
end
}.join($/) # return them all, concatenated with separator
end
end

How do you pass multiple arguments to nested route paths in Rails?

I am new to Rails and normally set up a link_to helper for a normal unnested route like so:
link_to "Delete", article_path(article.id), method: :delete, data: {confirm: "Are you sure?"}
However I am learning about nested routes and it seems I need to provide the path with two arguments for example:
link_to "(Delete)", article_comments_path(comment.article_id, comment.id), method: :delete, data:{comfirm: 'Are you sure?'}
However this does not seem to work. I have seen that you can format the link_to like this:
link_to 'Destroy Comment', [comment.article, comment], method: :delete, data: { confirm: 'Are you sure?' }
But this seems confusing to me as there is no path defined and the values necessary for the path arn't directly specified either.
Is it possible to format a nested link_to path like the unnested one above or does it need to be formatted as shown in the third example? If so could someone try to explain how this array format is translated into a url for Rails to execute?
Thanks
Route:
article_comment_path - DELETE - /articles/:article_id/comments/:id(.:format) - comments#destroy
I think your route would be something like articles/:article_id/comments/:id so you can do:
<%= link_to "Delete", article_comments_path(article_id: comment.article_id, id: comment.id), method: :delete, data:{comfirm: 'Are you sure?'} %>
And your 3rd link should be
<%= link_to 'Destroy Comment', polymorphic_path(comment.article, comment), method: :delete, data: { confirm: 'Are you sure?' } %>
For details check Polymorphic routes
Update
You just need to pass locals to your partial like:
<%= render "comment", locals: {article: comment.article, comment: comment} %>
and then use
<%= link_to "Delete", article_comments_path(article.id,comment.id), method: :delete, data:{comfirm: 'Are you sure?'}%>

Resources