Ho i seguenti modelli. Gli utenti hanno UserActions e una possibile UserAction può essere una ContactAction (UserAction è un polimorfismo). Ci sono altre azioni come loginAction ecc QuindiRuby on Rails 3: Combina i risultati di più has_many o has_many_through associazioni
class User < AR::Base has_many :contact_requests, :class_name => "ContactAction" has_many :user_actions has_many_polymorphs :user_actionables, :from => [:contact_actions, ...], :through => :user_actions end class UserAction < AR::Base belongs_to :user belongs_to :user_actionable, :polymorphic => true end class ContactAction < AR::Base belongs_to :user named_scope :pending, ... named_scope :active, ... end
L'idea è che un ContactAction unisce due utenti (con altre conseguenze all'interno della app) e ha sempre un ricezione e l'invio di un finale. Allo stesso tempo, ContactAction può avere stati diversi, ad es. scaduto, in sospeso, ecc.
Posso dire @user.contact_actions.pending
o @user.contact_requests.expired
per elencare tutte le richieste in sospeso/scadute che un utente ha inviato o ricevuto. Funziona bene
Quello che vorrei ora è un modo per unire entrambi i tipi di ContactAction. Cioè @user.contact_actions_or_requests
. Ho provato la seguente:
class User def contact_actions_or_requests self.contact_actions + self.contact_requests end # or has_many :contact_actions_or_requests, :finder_sql => ..., :counter_sql => ... end
ma tutti questi hanno il problema che non è possibile utilizzare finders o named_scopes aggiuntive rispetto all'associazione, ad esempio @user.contact_actions_or_requests.find(...)
o @user.contact_actions_or_requests.expired
.
Fondamentalmente, ho bisogno di un modo per esprimere un'associazione 1: n che ha due percorsi diversi. Uno è User -> ContactAction.user_id
, l'altro è User -> UserAction.user_id -> UserAction.user_actionable_id -> ContactAction.id
. E poi unire i risultati (ContactActions) in un'unica lista per ulteriori elaborazioni con named_scopes e/o finder.
Dal momento che ho bisogno di questa associazione in decine di posti letteralmente, sarebbe un grosso problema scrivere (e mantenere!) SQL personalizzato per ogni caso.
Preferirei risolvere questo problema in Rails, ma sono aperto anche ad altri suggerimenti (ad esempio una procedura di PostgreSQL 8.3 o qualcosa simile). La cosa importante è che alla fine, posso usare le funzioni di convenienza di Rails come con qualsiasi altra associazione e, cosa più importante, anche nidificarle.
Qualsiasi idea sarebbe molto apprezzata.
Grazie!
Per fornire una sorta-di risposta alla mia domanda:
Io probabilmente risolvere questo utilizzando una vista di database e aggiungere le associazioni appropriate a seconda delle necessità. Per quanto sopra, posso
- utilizzare SQL in finder_sql per creare la vista,
- nome "contact_actions_or_requests",
- modificare la clausola SELECT per aggiungere una colonna user_id,
- aggiungere un app /models/ContactActionsOrRequests.rb,
- e quindi aggiungere "has_many: contact_actions_or_requests" a user.rb.
Non so come gestirò l'aggiornamento dei record ancora - questo sembra non essere possibile con una vista - ma forse questo è un primo inizio.
Attualmente mi avere un caos di chiamate find_by_sql sparse per l'app. Devo ancora aggiornare questo per usare ARel e soprattutto il metodo #arel_table (vedi commento sotto). Quando lo faccio pubblicherò i miei risultati qui. – Jens
Come hai affrontato questo alla fine? –
Uso ancora finder_sql e counter_sql, ma ho estratto le stringhe SQL in un metodo di classe che includo poi tramite un proc. Questo è molto più pulito di prima, anche se devo ripensarci ora che ci stiamo spostando su Rails 4 e finder_sql è deprecato. – Jens