简体   繁体   English

NoMethodError - nil:NilClass 的未定义方法

[英]NoMethodError - undefined method for nil:NilClass

I've followed along with this guide: http://www.tobyh.com/thoughts/4 to make a 2-way friendship system for a social app.我遵循本指南: http : //www.tobyh.com/thoughts/4为社交应用程序制作了一个双向友谊系统。 After working on this for over a week straight, following that guide is by far the closest I've gotten to making this work, but the end product has a lot of serious problems.在连续研究了一个多星期之后,遵循该指南是迄今为止我最接近完成这项工作的方法,但最终产品有很多严重的问题。 Only the first third of it works - sending friend requests.只有前三分之一有效 - 发送好友请求。 Neither accepting nor declining friend requests works.接受或拒绝好友请求都不起作用。

To begin explaining this, here are the relevant parts of:为了开始解释这一点,以下是以下相关部分:

routes.rb路由文件

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

friendship.rb友谊.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友谊控制器.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, which are index pages that display every user, with pagination. _user.html.erb,这是显示每个用户的索引页,带有分页。 Here's the only relevant part of that:这是唯一相关的部分:

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

and show.html.erb, which displays user's profile pages.和 show.html.erb,它显示用户的个人资料页面。 On this page and the user index page, you can see and use an "Add Friend" button as long as you're logged in as someone other than that user.在此页面和用户索引页面上,只要您以该用户以外的其他人身份登录,您就可以看到并使用“添加朋友”按钮。 Also, due to indexing, if you try to send someone 2 friend requests, the 2nd friend request will fail.此外,由于索引,如果您尝试向某人发送 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>

Right now, sending friend requests seems to work regardless of whether you use the Add Friend link on a user's profile page or the Add Friend link next to their name in the users index.现在,无论您是使用用户个人资料页面上的“添加好友”链接还是用户索引中他们姓名旁边的“添加好友”链接,发送好友请求似乎都有效。 Here's a picture of the console after logging into user #3, adding user #2 as a friend from their profile page, and adding user #1 as a friend through the index page: http://i.imgur.com/MbsBKot.png And here's a picture of an SQL database browser also seeming to confirm that the initial friend requests are successfully being sent: http://i.imgur.com/cX45vm8.png "accepted" is set to false by default after sending a friend request since I'd like for it to be a "facebook style" friend request system, as opposed to a one-way "twitter style" one.这是登录用户 #3、从他们的个人资料页面将用户 #2 添加为朋友并通过索引页面将用户 #1 添加为朋友后的控制台图片: http : //i.imgur.com/MbsBKot。 png还有一张 SQL 数据库浏览器的图片,似乎也确认了初始好友请求发送成功: http : //i.imgur.com/cX45vm8.png “accepted”在发送好友后默认设置为 false请求,因为我希望它是一个“facebook 风格”的好友请求系统,而不是一个单向的“twitter 风格”。

Due to the large amount of time spent working on this problem, I've experienced a wide variety of problems and error messages, most of which no longer matter.由于在这个问题上花费了大量时间,我遇到了各种各样的问题和错误消息,其中大部分不再重要。 Starting from the point of receiving a friend request, here are the problems that currently exist after you click "Decline" on your profile page.从接收好友请求开始,以下是您在个人资料页面上单击“拒绝”后当前存在的问题。

At first, everything seems fine.起初,一切似乎都很好。 Your profile page refreshes and the "Friend request declined."您的个人资料页面会刷新并显示“好友请求被拒绝”。 message in friendships_controller.rb displays as intended. Friendships_controller.rb 中的消息按预期显示。 However, when you click on your Friend Requests tab, you'll see that the friend request you declined is still there.但是,当您单击“好友请求”选项卡时,您会看到您拒绝的好友请求仍然存在。 Here's a picture of that, without the flash message above and to the left: http://i.imgur.com/Dg1uTXf.png If you attempt to decline the friend request a 2nd time (or more), you receive the error message in the title of this problem.这是一张图片,没有上方和左侧的 Flash 消息: http : //i.imgur.com/Dg1uTXf.png如果您尝试第二次(或多次)拒绝好友请求,您会收到错误消息在这个问题的标题中。 Here's a picture of that too: http://i.imgur.com/XBhNtkF.png这也是一张照片: http : //i.imgur.com/XBhNtkF.png

That seems to suggest that it's failing because the friend request has already successfully been declined, right?这似乎表明它失败了,因为好友请求已被成功拒绝,对吗? As far as I can tell: nope!据我所知:不! I believe that's not true because of the contents of this picture: http://i.imgur.com/UOIYnHP.png After downloading a new copy of the database, it claims that there's an even larger number of friendships than there were before!我相信这是因为这幅画的内容不正确的: http://i.imgur.com/UOIYnHP.png下载数据库的新副本后,声称还有比有以前更大数量的友谊! 3 friend requests instead of 2, one of which has no friend_id attached to it. 3 个好友请求而不是 2 个,其中一个没有附加friend_id。 That would also explain why the friend request persists under the Friend Request tab.这也可以解释为什么好友请求会在“好友请求”选项卡下持续存在。

On top of that, if you log out, log into the account of the friend request sender, and attempt to send a 2nd friend request to the receiver, you'll receive this error message: http://i.imgur.com/q0WsVCB.png SQLite3::ConstraintException in FriendshipsController#create UNIQUE constraint failed: friendships.user_id, friendships.friend_id I'm pretty sure that's a result of adding indices to friendships, which prevents users from receiving 2 or more friend requests from the same person.最重要的是,如果您注销,登录好友请求发送者的帐户,并尝试向接收者发送第二个好友请求,您将收到此错误消息: http : //i.imgur.com/ q0WsVCB.png SQLite3::ConstraintException in FriendshipsController#create UNIQUE 约束失败:friendships.user_id, friends.friend_id我很确定这是向友谊添加索引的结果,这会阻止用户收到来自同一个人的 2 个或更多好友请求. That implies once again that clicking Decline doesn't truly delete the friend request, only the "friend_id" portion of it, which has the unintended effect of creating a 3rd friendship entry in the database.这再次意味着单击拒绝并不会真正删除好友请求,只会删除其中的“friend_id”部分,这会产生在数据库中创建第三个好友条目的意外效果。

Whew!哇! That was quite a bit of information, but that only covers the "Decline" link.这是相当多的信息,但仅涵盖“拒绝”链接。 Now for the "Accept" link!现在是“接受”链接!

If you log in, see a new friend request, and try to accept it, you'll receive the same error message that you would when attempting to decline a friend request 2 times in a row, but with this one referencing the update method instead of the destroy method: http://i.imgur.com/IHptXDu.png NoMethodError in FriendshipsController#update undefined method `update' for nil:NilClass I have no idea why this is.如果您登录,看到一个新的好友请求,并尝试接受它,您将收到与尝试连续 2 次拒绝好友请求时相​​同的错误消息,但此消息引用的是更新方法销毁方法: http ://i.imgur.com/IHptXDu.png NoMethodError in FriendshipsController#update undefined method `update' for nil:NilClass 我不知道为什么会这样。

As I was writing about and taking pictures of this problem, I noticed this repeated line: "friendship_path(id: request.id)" under show.html.erb, and thought about it compared to this database picture: http://i.imgur.com/UOIYnHP.png What if, when clicking Decline to delete the friendship request, it's only deleting the ID of the user who requested the friend request (which, in that picture, is the user_id, not the friend_id)?在写这个问题并拍照的时候,注意到show.html.erb下有这么一行重复:“friendship_path(id: request.id)”,对比这个数据库图片想了一下: http://i .imgur.com/UOIYnHP.png如果点击拒绝删除好友请求时,它只是删除了请求好友请求的用户的 ID(在该图中,是 user_id,而不是friend_id)怎么办? Could the problem be the format of the Decline and Accept links under show.html.erb, and everything else is fine..?问题可能是show.html.erb下的拒绝和接受链接的格式,其他一切都很好..?

I think I've written just about all I can write!我想我已经写了几乎所有我能写的东西! I'm sorry for how long this question was, and thank you for taking the time to read it;我很抱歉这个问题问了多久,感谢您花时间阅读它; I truly appreciate it from the bottom of my heart!我真的从心底里感激它!

I meant to add this over a week ago, but here's what ended up working for me.我打算在一周前添加这个,但这是最终对我有用的东西。

friendship.rb:友谊.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:用户.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: friends_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: 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 %>

Everything else is the same.其他一切都是一样的。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM