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

Mar*_*van 3 ruby ruby-on-rails

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

这是我的观看代码:

<% 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 %>
Run Code Online (Sandbox Code Playgroud)

我想检查用户是否跟随另一个用户,所以写了这个.它发生在两个用户ID,并查询数据库,并在发现匹配,否则为false返回true.但它总是回归真实.为什么是这样?

Rei*_*chs 7

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

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

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

  3. 旨在用于其真/假性质的方法(" 查询方法 ")应以?结尾,follows?而不是follows,

  4. 你的if语句是多余的,一旦条件做对了就可以安全地删除.在红宝石中,在条件语境中,我们更关心事物是否评价为真/假,而不是它们是字面true还是字面false.这意味着除了nilfalse将"truthy" 以外的任何东西.

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

  6. 您正在复制已使用关联提供给您的行为.

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

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
Run Code Online (Sandbox Code Playgroud)

注意:这里使用的followed_by?方法是使用双重调度,防止Demeter的(次要)法则违反一个用户直接了解另一个用户的关注者的状态.相反,第一个用户对象向第二个用户对象询问一个直接问题("你跟着我吗?")并将结果基于答案.(它本身也可能是一种有用的方法.)