Модель дружбы Rails 3: как игнорировать запрос на добавление в друзья?

У меня традиционная модель дружбы:

Пользовательская модель имеет:

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

Я хотел бы определить статус «друг» только в том случае, если запрос на добавление в друзья был отправлен и принят другим пользователем. Все работает нормально, за исключением того, что мне не удалось обработать часть «игнорировать запрос на добавление в друзья».

Что я пытаюсь сделать, так это: на странице профиля пользователя есть список запросов от другого пользователя, ожидающих утверждения. Затем пользователь может принять запрос на добавление в друзья (тогда он становится другом) или отклонить его (тогда дружеские отношения разрушаются).

Вот фрагмент кода в контроллере дружбы, когда он блокируется:

<h2 class="small_v_space">Waiting your approval</h2>
<ul>
  <% for user in @user.inverse_friends %>
    <% if user.friends.exists?(@user) and not @user.friends.exists?(user) %>
      <li>
        <%=h user.name %>
          (<%= link_to "Accept", friendships_path(:friend_id => user), :method => :post %>,
           <%= link_to "Ignore", friendship_path, :controller => :friendships, :method => :delete  %>)
      </li
    <% end %>
  <% end %>
</ul>

Проблема в том, что если я сделаю так, метод удаления удалит последнее добавленное отношение вместо того, которое связано с кнопкой игнорирования.

Давайте рассмотрим пример: Вот отношения, которые я хотел бы разрушить: User_id: 10 Friend_id: 6 Friendship_id: 18

Я на странице «показать» (профиль) пользователя, чей user_id равен 6. Я вижу, что пользователь 10 сделал запрос на добавление в друзья, который я хотел бы проигнорировать. Даже если бы мне удалось извлечь правильный Friendship_id, выполнив:

<%= link_to "Ignore", friendship_path(Friendship_id), :controller => :friendships, :method => :delete  %>)

Это приводит к «Не удается найти дружеские отношения с идентификатором = 18 [где user_id = 6]»

Кто-нибудь знает, как в этом случае я могу вызвать действие по уничтожению правильных отношений? Или я должен действовать по-другому?

Большое спасибо за любую подсказку!

ИЗМЕНИТЬ

Уничтожить действие контроллера дружбы:

def destroy
    @friendship = current_user.friendships.find(params[:id])
    if @friendship.friend.friends.exists?(current_user)
      @friendship.destroy
      flash[:notice] = "Removed friendship."
    else
      @friendship.destroy
      flash[:notice] = "Removed friend request."
    end
    redirect_to current_user
  end

РЕДАКТИРОВАТЬ 2:

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

Пользователь A отправляет запрос на добавление в друзья пользователю B (A=пользователь, B=друг в экземпляре класса). Если B принимает запросы, то создается другой экземпляр (B=пользователь, A=друг). Если существует отношение A->B и B->A, то A является другом B. В противном случае запрос остается в ожидании (или может быть проигнорирован, отклонен...).


person citraL    schedule 20.03.2012    source источник
comment
Мне кажется, вы слишком все усложняете. Я почти уверен, что для того, чтобы делать то, что вы хотите, все, что вам нужно, это модель друга и дружбы, а в модели дружбы у вас будет переменная int с именем status или что-то еще, что будет иметь разные значения в зависимости от того, отношения были приняты или нет. Но это не относится к делу. <%= link_to "Ignore", friendship_path(Friendship_id), :method => :delete %> должно работать, не могли бы вы показать действие уничтожения вашего контроллера дружбы?   -  person Ashitaka    schedule 20.03.2012
comment
@Ashitaka: спасибо за ответ! Я добавил действие уничтожения в вопросе. Вы правы, есть и другие способы сделать это, но я чувствую, что мог бы многому научиться, если бы смог сделать это таким образом. Проблема в том, что находясь внутри страницы показа пользователя_6, даже если передан правильный Friendship_id, он терпит неудачу, потому что он говорит, что не может найти Friendship_id=18 ГДЕ user_id =6 ... Я хотел бы как-то избавиться от этого user_id= 6 ... Я провел часы, пробуя множество вариантов, теперь я чувствую себя немного сбитым с толку :-/ ... в любом случае спасибо !   -  person citraL    schedule 20.03.2012
comment
Хорошо, чтобы решить эту проблему, нам нужно немного больше информации. Пожалуйста, покажите вашу модель отношений. А также, как вы различаете пользователя, который является вашим другом, и пользователя, который отправил вам запрос на добавление в друзья?   -  person Ashitaka    schedule 21.03.2012
comment
@Ashitaka: добавил модель отношений и ответил на ваш вопрос в EDIT2. Но я думаю, что вы были правы, я пошел по неправильному пути, я думаю, что было бы лучше работать с полем статуса (принято, проигнорировано, в ожидании) в модели дружбы... но все же, если вы видите, как я должен был сделать оригинал Кстати, буду рад узнать ;-)   -  person citraL    schedule 21.03.2012
comment
Смотрите мой отредактированный ответ! Может, на этот раз я правильно понял.   -  person Ashitaka    schedule 21.03.2012


Ответы (1)


Я редактирую весь свой ответ, потому что думаю, что нашел суть вашей проблемы. Когда пользователь пытается подружиться с кем-то, вы добавляете отношение к этому пользователю, но не добавляете его к другому пользователю. ТАК, current_user.friendships.find(params[:id]) ожидает, что current_user будет дружить с этим идентификатором, но эти отношения принадлежат не ему, а другому пользователю.

Я не уверен, что достаточно ясно выразился, но вот моя вторая попытка:

Ваша ссылка должна быть:

<%= link_to "Ignore", friendship_path(:id => friendship_id, :friend_id => user.id), :method => :delete  %>)

И затем ваше действие:

def destroy
  potential_friend = User.find(params[:friend_id])
  friend_request = potential_friend.friendships.find(params[:id])

  friendship = current_user.friendships.find_by_friend_id(potential_friend.id)
  if friendship.nil?      #Users are not friends and you want to delete the friend request
    friend_request.destroy
    flash[:notice] = "Removed friend request."
  else                    #Users are friends and you want to delete the friendship
    friendship.destroy
    friend_request.destroy
    flash[:notice] = "Removed friendship."
  end
  redirect_to current_user
end

Я не уверен, следует ли вам превратить это в настраиваемое действие. Как видите, он делает гораздо больше, чем просто уничтожает один объект.

person Ashitaka    schedule 21.03.2012
comment
Большое спасибо, Ашитака ... действительно, я думаю, что неправильно подошел к проблеме, и ваши несколько полезных комментариев было приятно получить, когда вы немного растерялись !!... Я не проверял вышеуказанное решение, потому что я перешел к другому варианту со статусом [ожидание, одобрено, проигнорировано]... Большое спасибо!! - person citraL; 22.03.2012
comment
Я рад, что вы передумали! Этот подход является более адекватным и простым для понимания, поэтому его легче реализовать. Удачи! - person Ashitaka; 22.03.2012