2010-09-21 16 views
32

Per impostazione predefinita, ActiveRecord accetta tutti i campi dalla tabella del database corrispondente e crea attributi pubblici per tutti loro.C'è un modo per rendere privati ​​gli attributi di Rails ActiveRecord?

Penso che sia ragionevole non rendere pubblici tutti gli attributi in un modello. Ancora di più, l'esposizione degli attributi che sono destinati ad uso interno ingombrare l'interfaccia del modello e viola il principio di incapsulamento.

Quindi, c'è un modo per rendere letteralmente alcuni degli attributi private?

Oppure, forse dovrei passare ad un altro ORM?

risposta

29

Jordini era la maggior parte del modo in cui ci

La maggior parte delle active_record succede in method_missing. Se si definisce il metodo di fronte, non colpirà method_missing per quel metodo, e usare il vostro al posto (in modo efficace la sovrascrittura, ma non realmente)

class YourModel < ActiveRecord::Base 

    private 

    def my_private_attribute 
    self[:my_private_attribute] 
    end 

    def my_private_attribute=(val) 
    write_attribute :my_private_attribute, val 
    end 

end 
+1

Qualsiasi motivo per cui non avrei/non potuto usare quanto segue per realizzare questo? privato attr_accessor my_private_attribute –

+2

@TC: perché in realtà non verranno tracciati correttamente gli attributi. i metodi write_attribute/read_attribute sono il modo in cui si interfacciano con active_record –

+0

in realtà, write_attribute non mantiene il valore su DB. Si dovrebbe chiamare self.save in seguito per aggiornare effettivamente il record nel DB. – Magne

5

bene, si può sempre sostituire i metodi ...

class YourModel < ActiveRecord::Base 

    private 

    def my_private_attribute 
    self[:my_private_attribute] 
    end 

    def my_private_attribute=(val) 
    self[:my_private_attribute] = val 
    end 

end 
+0

Sembra che questo dà un errore quando si utilizza l'aggiornamento dalla classe del modello. – NicolasWebDev

1

È possibile effettuare un metodo esistente privato:

YourClass.send(:private, :your_method) 
+1

questo in realtà non funziona con ActiveRecord, sfortunatamente, poiché i metodi di accesso non sono effettivamente definiti, sono creati con method_missing e un po 'di meta-programmazione. – brad

6

imbattuto in questo di recente. Se vuoi scrivere e leggere in privato e leggere qualcosa del genere

class YourModel < ActiveRecord::Base 

    attr_reader :attribute 

    private 

    attr_accessor :attribute 


end 

sembra funzionare bene per me. Puoi meditare con attr_reader, attr_writer e attr_accessor per decidere cosa dovrebbe essere esposto e cosa dovrebbe essere privato.

+1

Sono abbastanza sicuro che questo non funzionerà con gli attributi AR regolari, dal momento che sono non memorizzato in variabili di istanza (che funzionano con i metodi attr_ *). –

+1

Ho cercato questa risposta ovunque! Sembra che abbia funzionato ed era ESATTAMENTE quello che stavo cercando. Grazie! – ootoovak

+0

Da modello esterno posso fare 'your_model_instance [: my_private_attribute] =" Foo "' e modificare il valore dell'attributo. Molto brutto! –

0

Rendere l'impostazione privata genera errore ActiveRecord.

ho messo l'accesso codice di controllo nel metodo sovrascritto del setter pubblico controllando il chiamante:

def my_private_attribute=(val) 
    if (caller.first.include?('active_record/base.rb') || caller.first.include?('app/models/myclass.rb')) 
    self[:my_private_attribute] = val 
    else 
    raise Exception.new("Cannot set read-only attribute.") 
    end 
end 
1

Per me i metodi sia da Otto e jordinl stanno lavorando bene e fare RSpec per oggetto di classe a passare:

object.should_not respond_to :attribute 

ma quando io uso il metodo jordinl, ho un messaggio deprecazione di non scrivere nel database direttamente, ma utilizzare attr_writer invece.

UPDATE:

Ma il metodo descritto veramente "giusto" per farlo risulta essere semplice. Grazie a Mladen Jablanović e Christopher Creutzig from here. Per rendere metodo predefinito privato o protetto ... semplicemente ridefinirlo:

Class Class_name 

    private :method_name 
    protected :method_name_1 
end 

Che cosa è importante, non è necessario riscrivere la logica del metodo definito in precedenza.

Problemi correlati