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
Related
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
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.
I have the following code in my view:
<% if #user.marine? %>
<div>
<%= link_to("Close account".html_safe, deactivate_path(#user), method: :patch,
html_options = { role: "button", class: "button-small", data: "Are you certain?"
}) %>
</div>
<% end %>
On loading the page on the development server, this generates the error below, referring to the <% end %> line.
syntax error, unexpected ')', expecting => })
);#output_buffer.safe_append= syntax error, unexpected
keyword_end, expecting ')' '.freeze; end
Anyone got an idea what in the link-code is causing the error and how I should adjust for it?
I think it has to do with the data: "Are you certain?" part. This should pop-up a confirmation message. I also tried confirm: "Are you certain?" instead but that made no difference.
Update: I can't get the link to work unless I remove the entire html_options part. Just removing the data: "Are you certain?" part is not sufficient.
It is a hash key, there should be : or => instead of =. Try the following, grouping all html_options in one hash like this:
<%= link_to 'Close account'.html_safe,
deactivate_path(#user),
{ method: :patch, role: 'button', class: 'button-small', data: { confirm: 'Are you certain?'} } %>
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?'}%>
Right now, I have the following and it works:
<%= link_to 'stop service', service_path(:id => #service.id, 'service[stopped]' => true, method: :put, data: { confirm: 'Are you sure?' } %>
The link looks like this: http://localhost:3000/services/1?service%5Bstopped%5D=true
So the service[stopped] parameter gets submitted to the server as part of the query string. I need it to get submitted though as a POST/PUT form parameter instead. I tried adding 'service[stopped]' => true inside the data hash, but that didn't do anything.
You can try this.
<%= link_to 'stop service', service_path(:id => #service.id, 'service[stopped]' => true, data: { confirm: 'Are you sure?' }) , :method => :post %>
You can refer Rails 3 link_to generator for :post, :put, & :delete?