Reputation: 3945
I have the following helper method in rails 4.
def is_blog_owner?(blog_id)
if current_user && blog_id
blog = Blog.find_by(id: blog_id)
roles = current_user.roles_for_blog(blog)
roles.each do |role|
if role.role == 'Blog-Owner'
true
end
end
end
end
It has one problem, if the roles for a current user are nil it always seems to return true.
The way this currently works is that if a current user has a role of blog owner for a specific blog, then return true.
So if I visit (as user id 1) users/1/blogs/2
I will see edit and delete as shown below in the show.html.erb
How ever if I then log out and log in as user id 2 and visit users/1/blogs/2
I still see edit and delete. Which I should not.
So I threw a binding.pry
after roles
gets set and found roles
for user id 2 on user id 1's blog id of 2 to be nil This should mean that I should not see the edit and delete buttons, but I do ... What is going on?!
<h2><%[email protected]%> Profile</h2>
<p class="text-muted">
Welcome to your blog porfile page. Here you can manage the blog. You can edit or
delete the specific blog.
</p>
<% if is_blog_owner?(params[:id]) %>
<hr>
<h3>Action</h3>
<p class="text-muted">You can currently do the following actions: </p>
<%= link_to "Edit", edit_user_blog_path(current_user.id, @blog.id), :class => 'btn btn-success' %> |
<%= link_to "Delete", user_blog_path(current_user.id, @blog.id),
data: { confirm: "This is permenent. Are you sure?" },
:method => :delete,
:class => 'btn btn-danger'%>
<% end %>
I should ad that I did a <%= is_blog_owner?(params[:id]).inspect
and got a []
returned ... oO. Should it not return false?
Upvotes: 0
Views: 114
Reputation: 3963
Your problem is that roles.each ...
returns the enumerator it was called on - so essentially your method always returns roles
.
To sort it, change it thus:
def is_blog_owner?(blog_id)
if current_user && blog_id
blog = Blog.find_by(id: blog_id)
roles = current_user.roles_for_blog(blog)
roles.each do |role|
if role.role == 'Blog-Owner'
return true
end
end
end
return false
end
but it might be better to re-write it to make more sense about what it's doing. So it's looking through the roles the current users has for the blog, and returns true if any of them are 'Blog-Owner'?
Firstly, it might be better to use some authorisation process (like CanCan) to isolate this, but if you insist on a method of your own you could streamline it with .detect
:
def is_blog_owner?(blog_id)
if current_user && blog_id
blog = Blog.find_by(id: blog_id)
roles = current_user.roles_for_blog(blog)
roles.detect do |role|
role.role == 'Blog-Owner'
end
end
end
Which returns the first element in the enumerator that matches the block, otherwise it return nil if no element matches.
Upvotes: 0
Reputation: 27207
This construct is a problem for you:
roles.each do |role|
if role.role == 'Blog-Owner'
true
end
end
it returns the value of roles
, which presumably will be an Array
and thus always a true value. The standalone true
inside the block is not returned, that's not how .each
works. Generally you use .each
to process items in an array to change, or output based on each item, or perhaps perform some side-effect based on each one. The return value is always the Array
object, and not related to what you do inside the block.
Instead, you could use the method .any?
which seems to match your intent:
roles.any? do |role|
role.role == 'Blog-Owner'
end
Upvotes: 2