为什么这总是回归真实?轨道

时间:2011-04-19 22:11:59

标签: ruby-on-rails ruby

def follows(follower, followed)
follow = Follows.where("follower = ? AND followed = ?", follower, followed)
if follow
    true
  else 
    false
  end
end

这是我的观看代码:

<% if current_user.id == @user.id%>
  <p>This is you!</p>
<% else %>
  <% if follows(current_user.id, @user.id)%>
    <p>You already follow <%= @user.username %>
  <% else %>
    <p><%= link_to "Follow!", follow_path(@user.id) %></p>
   <% end %>
<% end %>

我想检查用户是否跟随另一个用户,所以写了这个。它需要两个用户ID,并查询数据库, 应该 在找到匹配时返回true,否则返回false。但它总是回归真实。这是为什么?

5 个答案:

答案 0 :(得分:7)

让我们先从一些风格和设计问题开始,然后以实际答案结束:

  1. 模型按惯例是单数的。否则只会让你工作更多。在这种情况下,我建议将Following作为合适的名称,例如“用户有很多关注”。

  2. 外键应以_id结尾。否则只会让你工作更多。所以follower_idfollowed_id

  3. 旨在用于其真/假性质的方法(“query methods”)应以?结尾,因此follows?代替follows

  4. 你的if语句是多余的,一旦条件做对了就可以安全删除。在ruby中,在条件语境中,我们更关心事物评估是否为真/假,而不是它们是字面true还是false。这意味着nilfalse以外的任何内容都将是“真实的”。

  5. 事实上,您的方法完全取决于User个对象已知的信息,这表明最好将其挂在这些对象之外,例如current_user.follows? other_user

    < / LI>
  6. 您正在使用关联重复已经提供给您的行为。

  7. 最后,考虑到所有这些因素,答案是:

    class User < ActiveRecord::Base
      has_many :followings, :class_name => 'Following', :foreign_key => 'followed_id'
      has_many :followers, :through => 'followings'
    
      def follows?(other)
        other.followed_by? self
      end
    
      def followed_by?(other)
        followers.include? other
      end
    end
    

    NB :此处followed_by?方法的使用是double dispatch的使用,可以防止一个用户直接了解该问题的(次要)Law of Demeter violation另一个用户的关注者的状态。相反,第一个用户对象向第二个用户对象询问一个直接问题(“你跟着我吗?”)并将结果基于答案。 (它本身也可能是一种有用的方法。)

答案 1 :(得分:3)

它总是返回true的原因是,即使没有找到记录,where()返回一个空数组。空数组是“true”。在其他新闻中,结构:

if (condition)
  true
else
  false
end

可以替换为:

condition

答案 2 :(得分:1)

follow实际上是ActiveRecord :: Relation的一个实例,而不是查询的结果集。要找出查询是否返回任何行,请使用follow.count。例如

if follow.count > 0
  true
else 
  false
end

答案 3 :(得分:1)

您可以使用present?。你的代码应该是

  if follow.present?
    true
  else 
    false
  end

答案 4 :(得分:0)

@rein Heinrichs的回答很棒。他为你提供了最好的Rails方法来解决它。但我想解释为什么你写的不起作用,以及你应该如何解决这个问题。

Follows.where(...)

返回一个数组,自己验证这个的简单方法是在rails控制台中运行该行(在控制台中键入rails c)。 数组(即使是空数组)不是nil,并且总是会计算为true

因此,要根据无论是否找到任何关注者的事实返回布尔值,只需检查where结果中的项目数量(使用size > 0present?

因此,您的follows函数可能已被重写为:

def follows(follower, followed)
  Follows.where("follower = ? AND followed = ?", follower, followed).present?
end

这实际上也很可读。希望这会有所帮助。