NoMethodError - nil的未定义方法:NilClass

时间:2016-05-05 16:13:56

标签: ruby-on-rails

我已按照本指南:http://www.tobyh.com/thoughts/4为社交应用制作双向友谊系统。经过一个多星期的工作后,按照该指南到目前为止我已经完成了这项工作,但最终产品存在很多严重的问题。只有前三分之一有效 - 发送好友请求。接受或拒绝朋友请求都不起作用。

要开始解释这一点,以下是相关部分:

的routes.rb

resources :friendships,   only: [:create, :update, :destroy]

friendship.rb

class Friendship < ActiveRecord::Base
  belongs_to :user
  belongs_to :friend, :class_name => 'User'
end

user.rb

class User < ActiveRecord::Base
  has_many :friendships,   dependent: :destroy
  has_many :received_friendships, class_name: "Friendship", foreign_key: "friend_id", dependent: :destroy

  has_many :active_friends, -> { where(friendships: { accepted: true}) }, through: :friendships, source: :friend
  has_many :received_friends, -> { where(friendships: { accepted: true}) }, through: :received_friendships, source: :user
  has_many :pending_friends, -> { where(friendships: { accepted: false}) }, through: :friendships, source: :friend
  has_many :requested_friendships, -> { where(friendships: { accepted: false}) }, through: :received_friendships, source: :user

  attr_accessor :remember_token, :activation_token, :reset_token (I've spent more than 20 hours on slogging through google and
stackoverflow alone, and I have a fuzzy memory of someone saying that attr_accessor might be relevant to this problem, but
I only saw it mentioned in a single question out of more than 20, so I'm not sure if it really is relevant.)

friendships_controller.rb

class FriendshipsController < ApplicationController

  def create
    @friendship = current_user.friendships.build(friend_id: params[:friend_id])
    if @friendship.save
      flash[:notice] = "Friend request sent!"
      redirect_to :back
    else
      flash[:error] = "Unable to send friend request."
      redirect_to :back
    end
  end

  def update
    @friendship = Friendship.find_by(id: params[:id])
    @friendship.update(:accepted, true)
    if @friendship.save
      redirect_to root_url, notice: "Friend request accepted."
    else
      redirect_to root_url, notice: "Unable to accept friend request."
    end
  end

  def destroy
    @friendship = Friendship.find_by(id: params[:id])
    @friendship.destroy
    flash[:notice] = "Friend request declined."
    redirect_to :back
  end

end

_user.html.erb,它是显示每个用户的索引页面,具有分页功能。这是其中唯一相关的部分:

<% if logged_in? && !current_user?(user) %>
  <%= link_to "Add Friend", friendships_path(:friend_id => user), :method => :post %>
<% end %>

和show.html.erb,显示用户的个人资料页面。在此页面和用户索引页面上,您可以查看和使用&#34;添加好友&#34;按钮,只要您以该用户以外的其他人身份登录即可。此外,由于索引,如果您尝试向某人发送2个朋友请求,则第二个朋友请求将失败。

        <% if logged_in? && !current_user?(@user) %>
          <%= link_to "Add Friend", friendships_path(:friend_id => @user), :method => :post %>
        <% end %>
...
    <ul class="nav nav-tabs">
      ...
      <% if logged_in? && current_user?(@user) %>
        <li><a data-toggle="tab" href="#friendreqs">Friend Requests</a></li>
      <% end %>
    </ul>
...
        <div id="friendreqs" class="tab-pane fade">
          <h3>Friend Requests</h3>
          <ul>
            <% if current_user?(@user) %>
              <% current_user.requested_friendships.each do |request| %>
              <li>
                <%= request.name %>
                <%= link_to "Accept",  friendship_path(id: request.id), method: "put" %>
                <%= link_to "Decline", friendship_path(id: request.id), method: :delete %>
              </li>
              <% end %>
            <% end %>
          </ul>
        </div>

现在,无论您是在用户的个人资料页面上使用“添加好友”链接还是在用户索引中使用其名称旁边的“添加好友”链接,发送好友请求似乎都有效。登录用户#3后,在控制台的图片中,将用户#2作为朋友从他们的个人资料页面添加,并通过索引页面将用户#1添加为朋友:http://i.imgur.com/MbsBKot.png此处&#39 ;一张SQL数据库浏览器的图片似乎也确认已成功发送了初始好友请求:http://i.imgur.com/cX45vm8.png&#34;已接受&#34;在发送好友请求后默认设置为false,因为我希望它是&#34; facebook风格&#34;朋友请求系统,而不是单向&#34;推特风格&#34;之一。

由于花费了大量时间处理此问题,我遇到了各种各样的问题和错误消息,其中大部分都不再重要。从收到朋友请求开始,点击&#34;拒绝&#34;在您的个人资料页面上。

起初,一切似乎都很好。您的个人资料页面会刷新,并且&#34;朋友请求被拒绝。&#34; friendships_controller.rb中的消息按预期显示。但是,当您点击“朋友请求”标签时,您会看到您拒绝的朋友请求仍然存在。这里有一张图片,没有上面和左边的flash消息:http://i.imgur.com/Dg1uTXf.png如果你第二次(或更多)尝试拒绝好友请求,你会收到标题中的错误消息问题。这也是一张照片:http://i.imgur.com/XBhNtkF.png

这似乎表明它失败了,因为好友请求已经成功被拒绝了,对吧?据我所知:不!我认为这不是真的,因为这张图片的内容:http://i.imgur.com/UOIYnHP.png下载了数据库的新副本后,它声称有一个甚至更大的数字友谊比以前好! 3个朋友请求而不是2个,其中一个没有附加friend_id。这也可以解释为什么朋友请求在“朋友请求”选项卡下仍然存在。

最重要的是,如果您注销,请登录好友请求发件人的帐户,并尝试向接收方发送第二个好友请求,您将收到以下错误消息:http://i.imgur.com/q0WsVCB.png FriendsitesController中的SQLite3 :: ConstraintException #create UNIQUE约束失败:friendships.user_id,friendships.friend_id 我非常确定这是为友情添加索引的结果,这会阻止用户从同一个人那里收到2个或更多朋友请求。这再次意味着单击拒绝并不能真正删除朋友请求,只有&#34; friend_id&#34;它的一部分,它具有在数据库中创建第三个友谊条目的意外效果。

呼!这是相当多的信息,但这只涵盖了&#34;衰落&#34;链接。现在为&#34;接受&#34;链接!

如果您登录,看到新朋友请求,并尝试接受它,您将收到与尝试连续2次拒绝朋友请求时相​​同的错误消息,但使用此消息引用update方法而不是destroy方法:http://i.imgur.com/IHptXDu.png FriendshipsController#update中的NoMethodError 未定义的方法`update&#39;为零:NilClass 我不知道为什么会这样。

当我写这个问题并拍照时,我注意到了这个重复的行:&#34; friendship_path(id:request.id)&#34;在show.html.erb下,并考虑与此数据库图片进行比较:http://i.imgur.com/UOIYnHP.png如果,当点击拒绝删除友情请求时,它只删除请求该朋友的用户的ID请求(在该图片中,是user_id,而不是friend_id)?问题可能是show.html.erb下的Decline和Accept链接的格式,其他一切都很好..?

我想我写的只是我能写的所有东西!对不起这个问题有多久了,谢谢你花时间阅读它;我衷心感激它!

1 个答案:

答案 0 :(得分:1)

我打算在一周前添加这个,但是这里最终为我工作了。

friendship.rb:

class Friendship < ActiveRecord::Base
  belongs_to :user
  belongs_to :friend, :class_name => 'User'
  validates :user_id, presence: true
  validates :friend_id, presence: true
end

user.rb:

class User < ActiveRecord::Base
  has_many :friendships,   dependent: :destroy
  has_many :received_friendships, class_name: "Friendship", foreign_key: "friend_id", dependent: :destroy

  has_many :passive_friends, -> { where(friendships: { accepted: true}) }, through: :received_friendships, source: :user
  has_many :active_friends, -> { where(friendships: { accepted: true}) }, :through => :friendships, :source => :friend
  has_many :requested_friendships, -> { where(friendships: { accepted: false}) }, through: :received_friendships, source: :user
  has_many :pending_friends, -> { where(friendships: { accepted: false}) }, :through => :friendships, :source => :friend

friendships_controller.rb:

class FriendshipsController < ApplicationController

  def create
    @friendship = current_user.friendships.build(friend_id: params[:friend_id])
    if @friendship.save
      flash[:notice] = "Friend request sent!"
      redirect_to :back
    else
      errors.add(:friendships, "Unable to send friend request.")
      redirect_to :back
    end
  end

  def update
    @friendship = Friendship.where(friend_id: [current_user, params[:id]], user_id: [current_user, params[:id]]).first
    @friendship.update(accepted: true)
    if @friendship.save
      redirect_to :back, notice: "Friend request accepted."
    else
      redirect_to :back, notice: "Unable to accept friend request."
    end
  end

  def destroy
    @friendship = Friendship.where(friend_id: [current_user, params[:id]]).where(user_id: [current_user, params[:id]]).last
    @friendship.destroy
    flash[:notice] = "Friend request declined."
    redirect_to :back
  end

end

show.html.erb:

  <% current_user.requested_friendships.each do |request| %>
    <% if request.id == @user.id %>
      <%= link_to "Accept Friend Request",  friendship_path(id: request.id), method: "put" %><br>
      <%= link_to "Decline Friend Request", friendship_path(id: request.id), method: :delete %>
    <% end %>
  <% end %>

  <% if logged_in? && !current_user?(@user) && Friendship.where(friend_id: [current_user, params[:id]], user_id: [current_user, params[:id]]).first == nil %>
    <%= link_to "Add Friend", friendships_path(:friend_id => @user), :method => :post %>
  <% end %>

其他一切都是一样的。