2010-02-14 19 views
5

Supongamos que tenemos un sitio de fotografía. Cualquier autor puede suscribirse para recibir actualizaciones de cualquier otro autor. Obviamente, si el autor está suscrito a un autor que B no significa que B está suscrito a A. Así construimos modelos¿Cómo crear relaciones "a dos lados" de muchos a muchos en Rails?

class Author < ActiveRecord::Base 
    has_many :subscriptions 
    has_many :subscribed_by_author, :through => :subscriptions, :source => :subscribed_to 
end 

class Subscription < ActiveRecord::Base 
    belongs_to :author 
    belongs_to :subscribed_to, :class_name => "Author", :foreign_key => "subscribed_to" 
end 

De esta manera podemos utilizar

  1. some_author.subscribed_by_author - la lista de los autores a los que some_author está suscrito.
  2. Para cualquier suscripción que podemos conocer ambos extremos (que se ha suscrito a quién)

Pero la cuestión es cómo conseguir que la lista de personas suscritas a algún autor utilizando sólo los carriles (no utilizando SQL normal), es decir get la respuesta a: "¿Quién está suscrito a some_author?"

Pregunta: ¿hay alguna posibilidad en Rails de que la relación funcione en ambos lados, es decir, no solo escribiendo some_author.subscribed_BY_author sino teniendo some_author_subscribed_TO_author? Si hay uno, ¿entonces qué es?

P.S. solución obvia es

  1. cambiar el diseño de base de datos, añadiendo una columna denominada "dirección"
  2. crear 2 registra cada vez que se crea una suscripción
  3. Añadir al modelo autor

    has_many: subscribed_BY_author ,: a través =>: suscripciones,: fuente =>: suscrito_ a,: condiciones => "dirección = 'por'"

    has_many: suscrito_TO_author,: a través =>: suscripciones,: fuente =>: suscrito_ a,: condición iones => "dirección = 'a'"

pero me pregunto si hay una solución sin cambiar el diseño de la base de datos.

Respuesta

0
# Author model 
has_many :subscriptions_to, :class_name => "Subscription", :foreign_key => "subscribed_to" 
has_many :subscribed_to_author, :through => :subscriptions_to, :source => :author 

Por lo que yo sé, ¡funciona! :)

+0

Desafortunadamente no lo hizo.Pero me dio la dirección correcta y el siguiente código funcionó #Autor modelo has_many: subscriptions_to,: class_name => "Subscription",: foreign_key => "subscribed_to" has_many: subscribed_to_author,: through =>: subscriptions_to,: source =>: autor Así que acepto esta respuesta, pero primero tiene que editarla para ser correcta :) ¡Gracias! –

+0

Siempre es un gran placer arreglar mis aswers :) – klew

2

Usaría HABTM simple para algo simple como este, pero vas a necesitar una tabla de combinación sin importar qué.

create_table :subscriptions do |t| 
    t.column :author_id, :integer 
    t.column :subscriber_id, :integer 
end 

Punto de Autor a la misma:

class Author < ActiveRecord::Base 
    has_and_belongs_to_many :subscribers 
    :class_name => "Author", 
    :join_table => "subscriptions", 
    :association_foreign_key => "subscriber_id" 

    def subscriptions # "subscribers" is already included above 
    self.subscribers.find(:all, :subscriber_id=>author.id) # hopefully not too 
    end              # much SQL 
end 

Si usted está realmente comprometido con sus nombres de método:

def subscribed_to_author 
    subscribers 
    end 

    def subscribed_by_author(author) 
    self.subscribers.find(:all, :subscriber_id=>author.id) 
    end 

crear algunas conexiones (que me gustaría hacer SubscriptionsController sea resty)

SubscriptionsController < ApplicationController 
    def create 
    @author = Author.find(params[:author_id] # author to be subscribed to 
    @user = current_user # user clicking the "subscribe" button 

    @author.subscribers << @user # assuming authors should only 
    @author.save     # be able to subscribe themselves 
    end 
end 

nombres para mostrar, o lo que sea

@author.subscribers.each do |s| 
    s.name 
end 
# ...or...and...also... 
<%= render :partial => @author.subscribers -%> 
<%= render :partial => @author.subscriptions -%> 
+0

¡Gracias! Eso fue muy útil. Ahora he encontrado dos métodos para resolver el problema. –

+0

@Sergii, de eso es de lo que estaba hablando en mi respuesta, que eliminé porque Eric es muy superior. –

Cuestiones relacionadas