2016-04-26 4 views
1

Ich habe ein Kontenmodell, wo ich möchte balance gelesen werden, aber es kann über private Methoden aktualisiert werden.Schienen: legen Sie ein Modellattribut als schreibgeschützt, aber ermöglichen die Aktualisierung über Methode

Derzeit

class Account < ActiveRecord::Base 
    def deposit(amount) 
    # do some stuff and then 
    update_balance(amount) 
    end 

    private 

    def update_balance(amount) 
    self.balance += amount 
    end 

end 

Dies ist jedoch immer noch möglich:

account = Account.first 
account.balance += 5 
account.save 

I für die oben möchte einen Fehler geben, aber noch in der Lage sein zu tun:

account.balance #=> 0 
account.deposit(5) 
account.balance #=> 5 
+0

Gibt es ':: balance =' Methode von Account? Woher kommt? Das ist, weil "Account.balance + = amount" auf "Account.balance = Account.balance + amount" erweitert wurde. –

+0

@ МалъСкрылевъ Ja, es gibt ein Kontostandsattribut, das hier nicht aufgeführt ist, da es in Rails ActiveRecord bereits festgelegt ist basierend auf dem Datenbankschema und sind bei der Definition des Modells nicht erforderlich. – amingilani

+0

Ich sehe kein solches Attribut in Rails-Dokumenten, validiere dein Schema/Modell –

Antwort

1

Sie können einen privaten Setter für die definieren Attribut:

class Account < ActiveRecord::Base 

    private 

    def balance=(the_balance) 
    write_attribute(:balance, the_balance) 
    end 
end 

Dann sind Sie nicht nennen es außerhalb Ihrer Account Klasse erlaubt:

Account.new(balance: 1234) 
# => ActiveRecord::UnknownAttributeError: unknown attribute 'balance' for 'Account' 

Account.new.balance = 1234 
# => NoMethodError: private method `balance=' called for <Account ...> 
0

ActiveRecord nicht nur die Schienen gem. Dies ist eine häufig verwendete pattern, die Spiegel-ähnliche Darstellung Ihrer DB in Ihrem Objekt bedeutet. So können alle Datenzugriffsmethoden in Ihren Modellen automatisch mit Rubin-Metaprogrammierungsmechanismen definiert werden.

Vielleicht ist es besser, Ihre Logik klar und bequem zu halten und schreiben Klasse AccountManager dass wird Werke auf der Account und können Sie eine solche Isolation, die Sie benötigen:

class AccountManager 
    def initialize(account) 
    @account = account 
    end 

    def deposit(amount) 
    # do some stuff and then 
    update_balance(amount) 
    end 

    private 

    def update_balance(amount) 
    @account.balance += amount 
    end 
end 
+0

Während dies funktioniert, verwende ich Ruby, und die Konvention ist es, ActiveRecord behandeln alle ORM-Aufgaben. – amingilani

+0

Geschäftslogik ist nicht "ORM-Aufgaben". Und Klassenextraktion wird in der modernen Entwicklung mit Schienen häufig verwendet. Übrigens, hüte dich vor fetten Modellen und hashigen Klassenflicken. – rootatdarkstar

+0

Ruby on Rails * .. sorry, ich tippe manchmal wie ein spaz. Was ich brauchte, war, den 'Setter' privat machen zu können, worauf BoraMa antwortete! – amingilani

Verwandte Themen