7 Dec
duccio

duccio il 7 December 2006 parla di Rails Snippet

Associazioni has_many :through polimorfiche

Ho dovuto fare un’associazione has_many :through usando il polimorfsmo e mi sono accorto che l’associazione funzionava solo in un verso!! Allora cercando, anche con poca fatica, ho trovato questo articolo The other side of polymorphic :through associations nel quale viene spiegato il problema con le soluzioni.

Vi riporto il problema applicato al mio caso così c’è un esempio in più.

Ho una tabella newsletters una sentmails nella quale raccolgo l’id della newsletter e gli id “degli oggetti” (qui si applica il polimorfismo) a cui l’ho spedita:

    1 class CreateNewlettersTable < ActiveRecord::Migration
    2   def self.up
    3     create_table :newsletters do |t|
    4        t.column :subject, :string
    5        t.column :body, :text
    6        t.column :html_body, :text
    7        t.column :created_at, :datetime
    8        t.column :updated_at, :datetime
    9     end
   10     
   11     create_table :sentmails do |t|
   12        t.column :newsletter_id, :integer
   13        t.column :subscriber_id, :integer
   14        t.column :subscriber_type, :string
   15     end
   16     
   17   end
   18 
   19   def self.down
   20     drop_table :newsletters
   21     drop_table :sentmails
   22   end
   23 end

In sentmails ci sono i vari oggetti a cui posso spedire newsletter, per fare in modo che questi oggetti si comportino come subscribers ho fatto una libreria acts_as_asubscriber:

    1 module ActiveRecord
    2   module Acts
    3     module Subscriber
    4       
    5       def self.included(base)
    6         base.extend(ClassMethods)  
    7       end
    8       
    9       module ClassMethods
   10         def acts_as_subscriber(options = {})
   11           write_inheritable_attribute(:acts_as_subscriber_options,{
   12             :subscriber_type => ActiveRecord::Base.send(:class_name_of_active_record_descendant, self).to_s,
   13             :from => options[:from]})
   14           
   15           class_inheritable_reader :acts_as_subscriber_options
   16 
   17           has_many :sentmails, :as => :subscriber
   18           has_many :newsletters, :through => :sentmails                
   19         end
   20       end
   21       
   22     end
   23   end
   24 end
   25 
   26 ActiveRecord::Base.class_eval do
   27   include ActiveRecord::Acts::Subscriber
   28 end

Poi dovrete fare altri due modelli Sentmail:

    1 class Sentmail < ActiveRecord::Base
    2   belongs_to :newsletter
    3   belongs_to :subscriber, :polymorphic => true
    4 end

e Newsletter:

    1 class Newsletter < ActiveRecord::Base
    2   has_many :sentmails
    3   has_many :subscribers, :through => :sentmails
    4 end
    5 

Così facendo se applicate acts_as_subscriber ad un modello User ad esempio potrete fare questo:

    1 @newsletters = User.find(1).newsletters.find(:all)

e vedere tutte le newsletter inviate all’utente 1. Se però fate:

    1 @users = Newsletter.find(1).users

vi darà errore!!

se però modificate il modello newsletter così:

    1 class Newsletter < ActiveRecord::Base
    2   has_many :sentmails
    3   has_many :subscribers, :through => :sentmails
    4   
    5   def users
    6     self.sentmails.collect {|a| a.subscriber}
    7   end
    8 end
    9 

allora vedrete che funziona e vi tirerà fuori tutti gli utenti a cui avete spedito la newsletter, il tutto a discapito delle prestazioni.

1 Commento a “Associazioni has_many :through polimorfiche”

  1. Lawanda il 12 June 2011 alle 20:52 dice:

    Kewl you should come up with that. Excllneet!

Scrivi un commento