2013-06-15 9 views
6

I un'applicazione dove un Post belongs_to :user Desidero conservare i post per gli utenti eliminati. Ciò può causare errori nella visualizzazione durante la visualizzazione di un post di cui è stato eliminato l'autore. Ho provato a fare questo:Implementazione di un pattern NullObject in Rails

class Post < ActiveRecord::Base 
    belongs_to :author, class_name: 'User', foreign_key: 'user_id' 

    def author 
    author || NullUser.new 
    super 
    end 
end 

Questo provoca un 'livello di stack per deep` errore. Perché? Ho potuto fare questo:

class Post < ActiveRecord::Base 
    belongs_to :user 

    def author 
    user || NullUser.new 
    end 

    def author=(user) 
    self.user = user 
    end 
end 

Ma non mi sembra giusto fare confusione con le mie associazioni in questo modo. Qual è il modo migliore per farlo?

+3

Nota a margine: In relazione al NullObjects e appena uscito, [Nulla] (https://github.com/avdi/nulla) di Avdi Grimm. –

risposta

13

Per rispondere alla tua domanda,

1. def author 
2. author || NullUser.new 
3. super 
4. end 

In linea 1, si sta definendo un metodo author. Quindi, nella riga 2, stai ancora chiamando il metodo dell'autore! Ciò continua a succedere e si ottiene un errore troppo profondo a livello di stack. Il modo corretto per farlo è,

def author 
    super || NullUser.new 
end 

Quindi non stai ancora chiamando il metodo dell'autore dentro di sé. Stai solo chiamando la super classe o restituendo NullUser. Nel caso in cui si verifica un errore pari a zero quando si sta chiamando super, quindi aggiungere un ulteriore controllo nullo:

def author 
    (super || NullUser.new) rescue NullUser.new 
end 

La dichiarazione di soccorso cattura tutti gli errori e poi tornare NullUser.new, in modo da non dovete preoccuparvi su super lanciare anche un errore.

EDIT:

Un altro modo di gestire eccellente gettare un'eccezione che sembra più bello:

def author 
    (super rescue nil) || NullUser.new 
end 
2

Se si desidera conservare i post per gli utenti eliminati, è meglio non "cancellarli" realmente.

Un'alternativa è "eliminazione software". Basta aggiungere una colonna booleana che dice "cancellato" o "inattivo".

Quindi, quando si intende eliminare un utente, controllare se ha post. Se niente, fallo cancellarlo. Se hai, elimina delicatamente.

In questo modo le cose sarebbero molto più semplici e pulite.

Un altro modo è "rubare" i post. Quando si elimina un utente, sposta tutti i suoi post sotto un account utente speciale, quindi cancellalo.

In entrambi i casi non si spezzerà l'associazione.

Problemi correlati