2017-03-02 4 views
9

Ich verwende Virtus, um Modelle zu erstellen, die Salesforce-Objekte darstellen.So speichern Sie eine Zeichenfolgenkennung in einem Modellattribut

Ich versuche Attribute zu erstellen, die über benutzerfreundliche Namen verfügen, die verwandt werden, um auf den Wert und die Methode zuzugreifen, die ich zu dem Abrufen eines Bezeichners "String" für die Variable verwenden kann.

Object.attribute #=> "BOB" 
Object.get_identifier(:attribute_name) #=> "KEY" 
# OR something like this 
Object.attribute.identifier #=> "KEY" 

Der angezeigte Name wird als Getter/setter und einer Kennung verwendet, die ich jedes Attribut speichern kann, an die API-Namen entspricht.

Hier ein Beispiel:

class Case 
include Virtus.model 

attribute :case_number, String, identifier: 'Case_Number__c' 

end 

c = Case.new(case_number: 'XXX') 
c.case_number #=> 'XXX' 
c.case_number.identifier #=> 'Case_Number__c' 

oder stattdessen eine Methode für das Attribut mit sich selbst, vielleicht ein sekundäres Verfahren wird für jeden Identifikator Satz erstellt:

c.case_number #=> 'XXX' 
c.case_number_identifier #=> 'Case_Number__c' 

Could I verlängern Virtus::Attribute und füge das hinzu? Wenn dem so ist, bin ich unsicher, wie ich das anstellen soll.

+0

Jaon, was ist mit der Prämie in dieser Frage passiert? Es scheint, als wäre es einfach in Luft verschwunden. Bitte hilf mir zu verstehen. – Raffael

+0

Ich habe keine Ahnung! Ich versuche herauszufinden, warum das Kopfgeld nie vollendet wurde. Ich setze ein anderes Bounty und ich werde es nach der 24 Stunden Wartezeit anschließen. –

Antwort

5

Affe sicherlich Virtus' Attribute Klasse Patchen ist eine Option .
Durch den Zugriff auf die Interna einer Bibliothek sind Sie jedoch anfällig für Refactorings im privaten Teil des Quellcodes dieser Bibliotheken.

Stattdessen könnten Sie ein Hilfsmodul verwenden, das diese Funktion kapselt. Hier ist ein Vorschlag, wie:

require 'virtus' 

# Put this helper module somewhere on your load path (e.g. your project's lib directory) 
module ApiThing 

    def self.included(base) 
    base.include Virtus.model 
    base.extend ApiThing::ClassMethods 
    end 

    module ClassMethods 
    @@identifiers = {} 

    def api_attribute(attr_name, *virtus_args, identifier:, **virtus_options) 
     attribute attr_name, *virtus_args, **virtus_options 
     @@identifiers[attr_name.to_sym] = identifier 
    end 

    def identifier_for(attr_name) 
     @@identifiers.fetch(attr_name.to_sym){ raise ArgumentError, "unknown API attribute #{attr_name.inspect}" } 
    end 
    end 

    def identifier_for(attr_name) 
    self.class.identifier_for(attr_name) 
    end 

end 

# And include it in your API classes 
class Balls 
    include ApiThing 

    api_attribute :color, String,  identifier: 'SOME__fancy_identifier' 
    api_attribute :number, Integer, identifier: 'SOME__other_identifier' 
    api_attribute :size, BigDecimal, identifier: 'THAT__third_identifier' 
end 

# The attributes will be registered with Virtus – as usual 
puts Balls.attribute_set[:color].type #=> Axiom::Types::String 
puts Balls.attribute_set[:number].type #=> Axiom::Types::Integer 
puts Balls.attribute_set[:size].type #=> Axiom::Types::Decimal 

# You can use the handy Virtus constructor that takes a hash – as usual 
b = Balls.new(color: 'red', number: 2, size: 42) 

# You can access the attribute values – as usual 
puts b.color  #=> "red" 
puts b.number  #=> 2 
puts b.size  #=> 0.42e2 
puts b.durability #=> undefined method `durability' [...] 

# You can ask the instance about identifiers 
puts b.identifier_for :color  #=> "SOME__fancy_identifier" 
puts b.identifier_for :durability #=> unknown API attribute :durability (ArgumentError) 

# And you can ask the class about identifiers 
puts Balls.identifier_for :color #=> "SOME__fancy_identifier" 
puts Balls.identifier_for :durability #=> unknown API attribute :durability (ArgumentError) 

Sie nicht Virtus benötigen, um Ihre API-Kennungen zu implementieren. Ein ähnliches Helfermodul könnte einfach attr_accessor s anstelle von Virtus-Attributen registrieren.
Virtus hat jedoch andere nützliche Funktionen wie die Hash-Konstruktoren und die Attributkosersion. Wenn es Ihnen nichts ausmacht, ohne diese Eigenschaften zu leben oder Ersatz zu finden, sollte der Virtus-Graben kein Problem sein.

HTH! :)

+0

Problem gelöst. das ist toll! Danke –

3

Ja, haben Sie Virtus::Attribute zu verlängern, konnte ich es mit arbeiten:

module Virtus 
    class AttributeSet < Module 
    def define_identifier(attribute, method_name, visibility, identifier) 
     define_method(method_name) { identifier } 
     send(visibility, method_name) 
    end 
    end 

    class Attribute 
    def define_accessor_methods(attribute_set) 
     attribute_set.define_reader_method(self, name,  options[:reader]) 
     attribute_set.define_writer_method(self, "#{name}=", options[:writer]) 
     attribute_set.define_identifier(self, "#{name}_identifier", options[:reader], options[:identifier]) 
    end 
    end 
end 

Dieses Refactoring werden könnte, aber Sie können c.case_number_identifier

+0

Was macht 'send (visibility, method_name)'? – Raffael

+0

Ich kopierte den Code von [define_reader_method] (https://github.com/solnic/virtus/blob/master/lib/virtus/attribute_set.rb#L133), um es konsistent zu machen. [send] (http://apidock.com/ruby/Object/send) ruft die Methode auf, vielleicht überschreibt virtus die Methode 'send', um in 'public_send' zu transformieren, weil' Sichtbarkeit' in diesem Fall öffentlich ist. – MaicolBen

+1

Vielen Dank für diesen Code! Beide Antworten lösen dieses Problem. –

Verwandte Themen