2017-03-02 8 views
9

Virtusを使用して、Salesforceオブジェクトを表すモデルを作成しています。文字列識別子をモデル属性に格納する方法

私は、その変数の識別子 "文字列"を取得するために使用できる値とメソッドにアクセスするためのフレンドリ名を持つ属性を作成しようとしています。

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

フレンドリ名は、getter/setterと、API名に対応する各属性を格納できる識別子として使用されます。ここで

は一例です:

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' 

または、代わりに属性自体にメソッドを有するので、多分二の方法は、各識別子のセットのために作成されます:

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

私はVirtus::Attributeを拡張することができこれを追加しますか?もしそうなら、私はそれについてどうやって行くのか分からない。

+0

Jaison、この疑問の恩恵はどうなりましたか?薄い空気の中に消えてしまったようですね。私の理解を助けてください。 – Raffael

+0

私は分かりません!なぜ賞金が決して完結しなかったのか自分自身を理解しようとしています。私は別の賞金を設定し、24時間待ってから接続します。 –

答えて

5

猿は確かにオプションですできます。
しかし、ライブラリの内部に到達すると、そのライブラリのソースコードのプライベートな部分でリファクタリングが脆弱になります。

代わりに、この機能をカプセル化するヘルパーモジュールを使用できます。

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) 

API識別子を実装するためにVirtusは必要ありません。同様のヘルパーモジュールは、Virtus属性の代わりにattr_accessorを登録するだけです。
しかし、Virtusには、ハッシュコンストラクタや属性コーディングのような便利な機能があります。これらの機能や代替品がなくても、Virtusを捨てても問題ありません。

HTH! :)

+0

問題が解決しました。これは素晴らしい!ありがとうございました –

3

うん、あなたはVirtus::Attributeを拡張してきた、私はそれがで動作するように得ることができる:

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 

これは、リファクタリングすることができますが、あなたがVirtus社Attributeクラスにパッチを適用c.case_number_identifier

+0

'send(visibility、method_name)'は何をしますか? – Raffael

+0

一貫性を持たせるために[define_reader_method](https://github.com/solnic/virtus/blob/master/lib/virtus/attribute_set.rb#L133)のコードをコピーしました。 [send](http://apidock.com/ruby/Object/send)がメソッドを呼び出します。おそらくvirtusは、 'public'send'で変換する' send'メソッドをオーバーライドします。これは、 'visibility'がpublicであるためです。 – MaicolBen

+1

このコードをありがとう!両方の答えがこの問題を解決します。 –

関連する問題