Cómo crear “dos laterales” relaciones muchos-a-muchos en los carriles?
-
20-09-2019 - |
Pregunta
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
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 usar
- some_author.subscribed_by_author -. La lista de los autores a los que está suscrito some_author
- Para cualquier suscripción que podemos conocer ambos extremos (que esté suscrito a quién)
Sin embargo, 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 obtener la respuesta a: "¿Quién está suscrito a some_author"
Pregunta: ¿hay alguna posibilidad de rieles para obtener la relación de trabajo a ambos lados es decir, no sólo la escritura some_author.subscribed_BY_author
pero tener some_author_subscribed_TO_author
? Si hay uno, entonces ¿qué es?
P.S. solución obvia es
- Cambiar el diseño de la base de datos, añadiendo una columna denominada "dirección"
- Crear 2 registros cada vez que se crea una suscripción
-
Añadir a la modelo de autor
has_many: subscribed_BY_author,: a través de =>: suscripciones,: fuente =>: subscribed_to,: condiciones => "dirección = 'por'"
has_many: subscribed_TO_author,: a través de =>: suscripciones,: fuente =>: subscribed_to,: condiciones => "dirección = 'a'"
Pero me pregunto si hay una solución sin cambiar el diseño de la base de datos.
Solución
# 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é - que funciona! :)
Otros consejos
que haría uso de HABTM llanura de algo tan simple como este, pero vas a necesitar una tabla de unión no importa qué.
create_table :subscriptions do |t|
t.column :author_id, :integer
t.column :subscriber_id, :integer
end
Punto de Autor a ella:
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
Crea 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
Los 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 -%>