2017-02-11 5 views
4

Ich habe eine User, die ein Stringemail Attribut hat. Allerdings, wenn ich mit einer E-Mail in meiner app zu tun habe, finde ich es wünschenswert, zuerst konvertiert es zu einem (nicht bestanden) Email Objekt, etwa so:Wie kann ich ein Objekt in eine Zeichenfolge für die Verwendung mit ActiveRecord-Abfragen umwandeln?

class User < ActiveRecord::Base 
    def email 
    Email.new(self.read_attribute :email) 
    end 
end 

Email#to_s und Email#to_str sind beide definiert werden einfach die ursprüngliche Zeichenkette (zB [email protected]), so ist es für den Client normalerweise ziemlich transparent, ob es sich um eine Email oder eine String handelt.

Dies funktioniert perfekt, wenn Attribute mit ActiveRecord zuweisen:

> email = Email.new('[email protected]') 
> user.email = email 

Active weiß, dass das email Attribut ist ein String und wandelt das Email Objekt entsprechend. Etwas rätselhaft, ist es dies nicht tun, wenn die Datenbank abfragt: Offensichtlich

> email = Email.new('[email protected]') 
> User.find_by email: email 
ActiveRecord::StatementInvalid: can't cast Email to string 

, kann ich

> User.find_by email: email.to_s 

rufen Sie einfach aber ist es eine Möglichkeit, diese Besetzung automatisch geschieht?

+0

Welche Version von Rails verwenden Sie? Für Rails 4.2 und höher können Sie ['attribute'] (http://apidock.com/rails/v4.2.7/ActiveRecord/Attributes/ClassMethods/attribute) verwenden, um das Typcasting-Verhalten zu steuern. – Max

+0

@Max Er müsste ein benutzerdefiniertes 'Type' für' attribute' definieren, um zu funktionieren, da das AR den gewünschten Typ bereits korrekt aus der Datenbank ableitet, aber der Standard 'Type' nicht weiß, wie er mit' Email' umgehen soll. Eine andere Option wäre, dass "Email" von "String" erbt (oder die Case-Gleichheitsoperatormethode auf "String" patchen). – coreyward

+0

@coreyward Ja, ich dachte an einen benutzerdefinierten Typ, der 'to_s' aufrufen würde. Ich dachte, es wäre sauberer als das Überschreiben von Dingen in 'ActiveModel', aber das Definieren eines benutzerdefinierten Typs könnte übertrieben sein, nur um' to_s' zu erhalten. Wahrscheinlich hängt es davon ab, ob dies ein allgemeines Muster für das OP ist und es für zusätzliche Klassen arbeiten muss. – Max

Antwort

0

Sie können die Getter-Methode in Ihrem Modell überschreiben, um sie zu konvertieren und die Zeichenfolge zurückzugeben.

4

This is the responsible object zum Umwandeln eines Objekts in eine Zeichenfolge in ActiveModel. Werfen Sie einen Blick auf die serialize Methode: Es hat keinen Fall für die Handhabung Email.

können Sie eine hinzufügen, indem Sie die Klasse erweitern:

module EmailSupport 
    def serialize(value) 
    case value 
    when Email then value.to_s 
    else super 
    end 
    end 
end 

ActiveModel::Type::ImmutableString.include(EmailSupport) 

User.find_by email: Email.new('[email protected]') 
Verwandte Themen