2011-04-10 23 views
20

Actualmente estoy trabajando en una pequeña aplicación de redes sociales y en este momento estoy tratando de crear un modelo que representa amistades entre usuarios. Esto es lo que me ocurrió hasta el momento:¿Cómo implementar un modelo de amistad en Rails 3 para una aplicación de red social?

class User < ActiveRecord::Base 

    # ... 
    has_many :friendships 
    has_many :friends, :through => :friendships 

end 

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

Mi amistad modelo tiene un campo confirmado como booleano, que me gustaría utilizar para definir una amistad como pendiente o confirmada.

¿Cómo puedo acceder a todas las solicitudes pendientes para un determinado usuario? ¿De alguna manera puedo definir usando el método de alcance de Rails? Algo como

current_user.friendships.requests # => [Friendship, Friendship, ...] 

sería genial.

¿Cómo puedo hacer que esta asociación sea bidireccional? Puedo simplemente añadir otra amistad una vez que se ha confirmado una solicitud de amistad de tal manera que mi mesa amistad tendría un aspecto similar a este:

| user_id | friend_id | confirmed | 
----------------------------------- 
| 1  | 2   | true  | 
| 2  | 1   | true  | 
+1

¿Cómo un amigo difieren de otro usuario, aparte del hecho de que están vinculados a través de una amistad? –

Respuesta

30

Para tener acceso a todas las amistades pendientes se puede utilizar una asociación:

has_many :pending_friends, 
     :through => :friendships, 
     :source => :friend, 
     :conditions => "confirmed = 0" # assuming 0 means 'pending' 

Para hacer el bidireccional amistad, es posible que desee reemplazar su columna booleano confirmado con una cadena estado columna que tiene una de las los siguientes tres valores: 'pendiente', 'solicitado' y 'aceptado' (opcionalmente 'rechazado'). Esto ayudará a realizar un seguimiento de quién hizo la solicitud de amistad.

Cuando se envía una solicitud de amistad (digamos de Foo a Bar), crea dos registros de amistad (encapsulados en una transacción): uno solicitado y otro pendiente para reflejar resp. ese Bar tiene una amistad solicitada por Foo y Foo tiene una amistad pendiente con Bar.

def self.request(user, friend) 
    unless user == friend or Friendship.exists?(user, friend) 
     transaction do 
     create(:user => user, :friend => friend, :status => 'pending') 
     create(:user => friend, :friend => user, :status => 'requested') 
     end 
    end 
    end 

Cuando se acepta la amistad (por ejemplo, por Bar), ambos registros de amistad se establecen para ser aceptados.

def self.accept(user, friend) 
    transaction do 
     accepted_at = Time.now 
     accept_one_side(user, friend, accepted_at) 
     accept_one_side(friend, user, accepted_at) 
    end 
    end 

    def self.accept_one_side(user, friend, accepted_at) 
    request = find_by_user_id_and_friend_id(user, friend) 
    request.status = 'accepted' 
    request.accepted_at = accepted_at 
    request.save! 
    end 

Esto se cubre en gran medida en el capítulo 14 del libro de Michael Hartl Railspace y Aurelio Prochazka. Aquí está el source code que debería ayudarlo a refinar su solución.

+0

Solo para decir gracias, me has ayudado con el mismo problema, pero en PHP. =) +1 – JCM

+0

¿Sabe a qué atributos debe ser accesible en el Modelo de amistad? Supongo que solo el atributo de estado debe ser accesible. ¿Estoy en lo correcto? – pratski

+0

hi @mbreining me encontré con su solución de hoy, no sé si en realidad hay una solución más potente que esto, pero yo creo que no es una buena idea para crear dos líneas de una relación entre 2 usuarios en la tabla de amistades, puedo enviar una nueva pregunta aquí si puede ayudar http://stackoverflow.com/questions/19339596/the-best-way-to-implement-a-friendship-model-in-rails gracias – medBo

1

Te recomiendo el libro RailsSpace: La construcción de un sitio web de redes sociales. Explica claramente cómo implementar un modelo de amistad. Aunque no es extensible a otras formas de relación, pero es bastante aplicable para su problema.

+0

¿usted sabe qué atributos debe ser accesible en el Modelo de Amistad? Supongo que solo el atributo de estado debe ser accesible. ¿Estoy en lo correcto? – pratski

4

Una respuesta corta es sí. Simplemente haga otro registro de amistad para representar una asociación bidireccional.

me escribió una joya llamada has_friendship para este tipo de problema. Todo lo que necesita hacer es caída en has_friendship en su modelo, y todas las asociaciones y métodos serán atendidos.

Espero que esto ayude!

Cuestiones relacionadas