辅助方法即使在证明错误的情况下也始终返回true

时间:2014-05-18 19:20:56

标签: ruby-on-rails ruby

我在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

它有一个问题,如果当前用户的角色为零,则它似乎总是返回true。

目前的工作方式是,如果当前用户具有特定博客的博客所有者角色,则返回true。

因此,如果我访问(作为用户ID 1)users/1/blogs/2,我将看到编辑和删除,如下所示show.html.erb如果我然后注销并以用户ID 2登录并访问users/1/blogs/2我仍然看到编辑和删除。我不应该这样做。

所以我在设置binding.pry之后扔了roles,并且在用户ID 1上找到roles用户ID为2的博客ID为nil这应该意味着我不应该看到编辑和删除按钮,但我确实......发生了什么?!

<h2><%=@blog.title%> 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 %>

我应该知道我做了一个<%= is_blog_owner?(params[:id]).inspect并且[]返回了...... oO。它不应该返回假吗?

2 个答案:

答案 0 :(得分:2)

这个结构对你来说是一个问题:

  roles.each do |role|
    if role.role == 'Blog-Owner'
      true
    end
  end

它返回roles的值,大概是Array,因此总是一个真值。不会返回块内的独立true,而不是.each的工作方式。通常,您使用.each来处理数组中的项目以根据每个项目进行更改或输出,或者根据每个项目执行一些副作用。返回值始终是Array对象,与块内部的操作无关。

相反,您可以使用似乎符合您意图的方法.any?

  roles.any? do |role|
    role.role == 'Blog-Owner'
  end

答案 1 :(得分:0)

你的问题是roles.each ...返回它被调用的枚举器 - 所以基本上你的方法总是返回roles

要对其进行排序,请进行更改:

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

但重写它可能会更好,以便更好地理解它所做的事情。因此,它会查看当前用户对博客所拥有的角色,如果他们中的任何一个是“博客所有者”,则返回true?

首先,最好使用一些授权流程(例如CanCan)来隔离它,但如果您坚持使用自己的方法,则可以使用.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

返回枚举器中与块匹配的第一个元素,否则如果没有元素匹配则返回nil。