删除使用自引用关联添加的“朋友”

时间:2012-11-23 00:33:57

标签: ruby-on-rails

我可以实现反向关系,因此如果UserA添加了UserB,那么它会在B的配置文件中显示UserA,反之亦然。 但是,如果UserA添加了UserB,我无法弄清楚如何让UserB将UserA作为朋友删除。 我尝试了很多不同的方法,但每次我改变一些东西都会把问题转移到其他地方!我不知道基本问题是否是:

  • 一个。如何定义FriendshipsController销毁方法
  • 湾我是否需要专门处理的另一个控制器 InverseFriendships destroy
  • ℃。如果我需要自定义路线
  • d。如果以上所有都可以,但我的观点中的代码(具体而言) _suggested_connections部分)正在调用错误的控制器 和/或路线
  • 即或者以上都不是。

以下代码段:

class FriendshipsController < ApplicationController

      def destroy
        @friendship = current_user.friendships.find(params[:id])
        @friendship.destroy
        flash[:notice] = "Removed friendship."
        redirect_to current_user
      end

在视图中

        <% @user.inverse_friends.each do |inverse_friendship| %>
      <li>
        <%= inverse_friendship.name %>
        <%= link_to "remove", @user.inverse_friendships, :method => :delete, :class => "btn-small btn-danger" %><br />
        <%= image_tag inverse_friendship.avatar(:thumb) %>

我的模特:

class Friendship < ActiveRecord::Base
  belongs_to :user
  belongs_to :friend, class_name: 'User'
  attr_accessible :friend_id, :user_id
end 

 class User < ActiveRecord::Base

    has_many :friendships, dependent: :destroy
    has_many :friends, through: :friendships
    has_many :inverse_friendships, dependent: :destroy, class_name: "Friendship", foreign_key: "friend_id"
has_many :inverse_friends, through: :inverse_friendships, source: :user

路线:

    resources :friendships

  authenticated :user do
    root :to => 'home#index'
  end
  root :to => "home#index"
  devise_for :users, :controllers => { :registrations => :registrations }
  resources :users

1 个答案:

答案 0 :(得分:1)

你的主要问题是:

  

一个。如何定义FriendshipsController销毁方法

您正在寻找friendship中的current_user.friendships,但它并不存在。它位于inverse_friendships

您需要检查两个关联,或让控制器知道您正在寻找哪一个。后者可能更可取,因为虽然它们是同一类,但它们不同的资源。这样的事情可能是:

# In routes, route inverse friendships to the same controller, but with a
# different path (I'm routing everything here, you may not need that.)
resources :friendships
resources :inverse_friendships, :controller => 'friendships'


# Then in your friendships controller, use the path to determine which 
# collection you're working with:
#
def destroy
  @friendship = collection.find(params[:id])
  # ...
end

# the other collection methods would use the same collection, if you needed them,
# for example:
def create
  @friendship = collection.build(params[:friendship])
  # ..
end

protected

# simple case statement here, but you get the idea
def collection
  case request.path
  when /\/inverse_friendships/ then current_user.inverse_friendships
  else current_user.friendships
  end
end

最后,在你看来,你会走向一个反向友谊,如:

<%= link_to "remove", inverse_friendship_path(friendship), :method => :delete %>

正常的友谊可以使用较短的形式或完整的命名路线:

<%= link_to "remove", friendship, :method => :delete %>
OR
<%= link_to "remove", friendship_path(friendship), :method => :delete %>

编辑:搜索两个关联。

当然,如果您想保持简单,并且inverse_friends没有其他用途可以作为单独的资源,那么您可以随时......

def destroy
  id, cid = params[:id], current_user.id

  # search both associations (two queries)
  @friendship = current_user.friendships.find_by_id(id) ||
                  current_user.inverse_friendships.find(id)

  # or query friendship looking for both types
  @friendship = Friendship.
                  where("user_id = ? OR friend_id = ?", cid, cid).find(id)

  # ...
end