ruby-on-rails - sirve - todo sobre ruby on rails
¿Cómo implementar un modelo de amistad en Rails 3 para una aplicación de redes sociales? (5)
La última referencia:
http://railscasts.com/episodes/163-self-referential-association
Actualmente estoy trabajando en una pequeña aplicación de redes sociales y en este momento estoy tratando de crear un modelo que represente amistades entre los usuarios . Esto es lo que se me ocurrió hasta ahora:
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 modelo de amistad tiene un campo confirmado como booleano que me gustaría usar para definir una amistad como pendiente o confirmada.
¿Cómo puedo acceder a todas las solicitudes pendientes para un determinado usuario? ¿Puedo definir esto de alguna manera usando el método de alcance de Rails? Algo como
current_user.friendships.requests # => [Friendship, Friendship, ...]
sería genial.
¿Cómo puedo hacer esta asociación bidireccional? Simplemente agrego otra amistad una vez que uno ha confirmado una solicitud de amistad tal que mi tabla de amistad se vea similar a esto:
| user_id | friend_id | confirmed |
-----------------------------------
| 1 | 2 | true |
| 2 | 1 | true |
Lea en este tutorial que ilustra un modelo de relación en Rails Tutorials. Debe ser exactamente lo que estás buscando.
Para acceder a todas las amistades pendientes puedes usar una asociación:
has_many :pending_friends,
:through => :friendships,
:source => :friend,
:conditions => "confirmed = 0" # assuming 0 means ''pending''
Para hacer que la amistad sea bidireccional, puede reemplazar su columna confirmada booleana por una columna de estado de cadena que tenga uno de los tres valores siguientes: ''pendiente'', ''solicitada'' y ''aceptada'' (opcionalmente ''rechazada''). Esto ayudará a mantener un registro de quién hizo la solicitud de amistad.
Cuando se envía una solicitud de amistad (por ejemplo, de Foo a Bar), se crean dos registros de amistad (encapsulados en una transacción): uno solicitado y otro pendiente para reflejar la resp. que Bar tiene una amistad solicitada de 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 como 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 parte en el capítulo 14 del libro Railspace de Michael Hartl y Aurelius Prochazka. Aquí está el código fuente que debería ayudarlo a refinar su solución.
Te recomiendo el libro RailsSpace: Construyendo 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, es bastante aplicable a su problema.
Una respuesta corta es sí. Solo haz otro registro de amistad para representar la asociación bidireccional.
Escribí una gema llamada has_friendship para este tipo de problema. Todo lo que necesita hacer es dejar has_friendship
en su modelo, y todas las asociaciones y métodos serán atendidos.
¡Espero que esto ayude!