Class: FamilytreeV2::Communicator

Inherits:
Object
  • Object
show all
Defined in:
lib/ruby-fs-stack/familytree/communicator.rb

Constant Summary collapse

Base =
'/familytree/v2/'

Instance Method Summary collapse

Constructor Details

#initialize(fs_communicator) ⇒ Communicator

params

fs_communicator: FsCommunicator instance



17
18
19
# File 'lib/ruby-fs-stack/familytree/communicator.rb', line 17

def initialize(fs_communicator)
  @fs_communicator = fs_communicator
end

Instance Method Details

#combine(person_array) ⇒ Object

Combines person into a new person

Params

  • person_array - an array of person IDs.



248
249
250
251
252
253
254
255
256
257
258
# File 'lib/ruby-fs-stack/familytree/communicator.rb', line 248

def combine(person_array)
  url = Base + 'person'
  version_persons = self.person person_array, :genders => 'none', :events => 'none', :names => 'none'
  combine_person = Org::Familysearch::Ws::Familytree::V2::Schema::Person.new
  combine_person.create_combine(version_persons)
  familytree = Org::Familysearch::Ws::Familytree::V2::Schema::FamilyTree.new
  familytree.persons = [combine_person]
  res = @fs_communicator.post(url,familytree.to_json)
  familytree = Org::Familysearch::Ws::Familytree::V2::Schema::FamilyTree.from_json JSON.parse(res.body)
  return familytree.persons[0]
end

#contributor(id_or_ids) ⇒ Object

params

id_or_ids should be a string of the persons identifier. For the ‘me’ person, use :me or ‘me’. Can also accept an array of ID strings. options accepts a hash of parameters as documented by the API. For full parameter documentation, see DevNet

Example

# communicator is an authenticated FsCommunicator object
# Request a person with no assertions, only the version.
p = communicator.familytree_v2.person :me, :names => 'none', :genders => 'none', :events => 'none'

p.version # => '90194378772'
p.id # => 'KW3B-NNM'


298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
# File 'lib/ruby-fs-stack/familytree/communicator.rb', line 298

def contributor(id_or_ids)
  if id_or_ids.kind_of? Array
    multiple_ids = true
    url = Base + 'contributor/' + id_or_ids.join(',')
    props = properties()
    if id_or_ids.size > props['contributor.max.ids'] 
      contributors = []
      id_or_ids.each_slice(props['contributor.max.ids']) do |ids_slice|
        contributors = contributors + contributor(ids_slice)
      end
      return contributors
    end
  else
    multiple_ids = false
    id = id_or_ids.to_s
    if id == 'me'
      url = Base + 'contributor'
    else
      url = Base + 'contributor/' + id
    end
  end
  response = @fs_communicator.get(url)
  familytree = parse_response(response)
  if multiple_ids
    return familytree.contributors
  else
    return familytree.contributors.first
  end
end

#match(id_or_hash, hash = {}) ⇒ Object

Params

id_or_hash - Either an ID or a hash of match parameters matching API doc hash - if the first parameter is an ID, then this will contain the hash of match parameters.



106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
# File 'lib/ruby-fs-stack/familytree/communicator.rb', line 106

def match(id_or_hash, hash={})
  url = Base + 'match'
  if id_or_hash.kind_of? String
    id = id_or_hash
    url += "/#{id}"
    params_hash = hash
  elsif id_or_hash.kind_of? Hash
    id = nil
    params_hash = id_or_hash
  else
    raise ArgumentError, "first parameter must be a kind of String or Hash"
  end
  url += add_querystring(params_hash) #"?" + FsUtils.querystring_from_hash(params_hash) unless params_hash.empty?
  response = @fs_communicator.get(url)
  familytree = Org::Familysearch::Ws::Familytree::V2::Schema::FamilyTree.from_json JSON.parse(response.body)
  # require 'pp'
  # pp familytree
  familytree.matches[0]
end

#pedigree(id_or_ids, options = {}) ⇒ Object



260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
# File 'lib/ruby-fs-stack/familytree/communicator.rb', line 260

def pedigree(id_or_ids, options = {})
  if id_or_ids.kind_of? Array
    multiple_ids = true
    url = Base + 'pedigree/' + id_or_ids.join(',')
  else
    multiple_ids = false
    id = id_or_ids.to_s
    if id == 'me'
      url = Base + 'pedigree'
    else
      url = Base + 'pedigree/' + id
    end
  end
  url += add_querystring(options)
  # url += add_querystring(options)
  response = @fs_communicator.get(url)
  familytree = parse_response(response)
  if multiple_ids
    return familytree.pedigrees
  else
    pedigree = familytree.pedigrees.find{|p| p.requestedId == id }
    pedigree ||= familytree.pedigrees.first if id == 'me'
    return pedigree
  end
end

#person(id_or_ids, options = {}, &block) ⇒ Object

params

id_or_ids should be a string of the persons identifier. For the ‘me’ person, use :me or ‘me’. Can also accept an array of ID strings. options accepts a hash of parameters as documented by the API. For full parameter documentation, see DevNet

Example

# communicator is an authenticated FsCommunicator object
# Request a person with no assertions, only the version.
p = communicator.familytree_v2.person :me, :names => 'none', :genders => 'none', :events => 'none'

p.version # => '90194378772'
p.id # => 'KW3B-NNM'

Blocks

A block is available for this method, so that you can register a callback of sorts for when a read has been completed.

For example, if I were to send 500 person IDs to this method and the current person.max.ids was 10, 50 person reads would be performed to gather all of the records. This could take some time, so you may want to present a progress of sorts to the end-user. Using a block enables this to be done.

ids = [] #array of 500 ids
running_total = 0
persons = communicator.familytree_v2.person ids, :parents => 'summary' do |people|
  running_total += ps.size
  puts running_total
end

# If you are only requesting a single individual, the block will be passed a single person record
person = communicator.familytree_v2.person :me do |p|
  puts p.id
end

500 Errors

Occasionally, the FamilySearch API returns 500 errors when reading a person record. This is problematic when you are requesting 100+ person records from the person read because it may happen towards the end of your entire batch and it causes the entire read to fail. Rather than fail, it does the following.

If you are requesting multiple IDs and a 500 is thrown when requesting 10 records, it is possible that only 1 of the 10 person records actually caused the problem, so this will re-request the records individually.

If a single record throws a 500, then the response will be an empty person record with only an ID.



68
69
70
71
72
73
74
# File 'lib/ruby-fs-stack/familytree/communicator.rb', line 68

def person(id_or_ids, options = {}, &block)
  if id_or_ids.kind_of? Array
    return multi_person_read(id_or_ids,options,&block)
  else
    return single_person_read(id_or_ids.to_s,options,&block)
  end
end

#propertiesObject



328
329
330
331
332
333
334
335
336
337
338
339
340
341
# File 'lib/ruby-fs-stack/familytree/communicator.rb', line 328

def properties
  if @properties_hash
    return @properties_hash
  else
    url = Base + 'properties'
    response = @fs_communicator.get(url)
    familytree = parse_response(response)
    @properties_hash = {}
    familytree.properties.each do |prop|
      @properties_hash[prop.name] = prop.value.to_i
    end
    return @properties_hash
  end
end

#relationship(base_id, options) ⇒ Object

Params

  • base_id - The root person for creating the relationship

  • options - Should include either :parent, :spouse, or :child. :lineage and :event is optional. Other Relationship Read parameters may be included in options such as :events => ‘all’, :characteristics => ‘all’, etc.

If the :lineage is set, the parent-child relationships will be written via a characteristic. Otherwise, an exists assertion will be created to just establish the relationship.

Example

communicator.familytree_v2.relationship 'KWQS-BBQ', :parent => 'KWQS-BBT'
communicator.familytree_v2.relationship 'KWQS-BBQ', :parent => 'KWQS-BBT'


203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
# File 'lib/ruby-fs-stack/familytree/communicator.rb', line 203

def relationship(base_id,options)
  begin
    r_type = get_relationship_type(options)
    with_id = options[r_type.to_sym]
    url = "#{Base}person/#{base_id}/#{r_type}/#{with_id}"
    options.reject!{|k,v| k.to_s == 'spouse'}
    url += add_querystring(options)
    res = @fs_communicator.get(url)
    familytree = Org::Familysearch::Ws::Familytree::V2::Schema::FamilyTree.from_json JSON.parse(res.body)
    person = familytree.persons.find{|p|p.requestedId == base_id}
    return person
  rescue RubyFsStack::NotFound
    return nil
  end
end

#save_person(person) ⇒ Object



76
77
78
79
80
81
82
83
84
85
86
87
88
# File 'lib/ruby-fs-stack/familytree/communicator.rb', line 76

def save_person(person)
  if person.id.nil?
    url = Base + 'person'
  else
    url = Base + 'person/' + person.id
  end
  familytree = Org::Familysearch::Ws::Familytree::V2::Schema::FamilyTree.new
  familytree.persons = [person]
  response = @fs_communicator.post(url,familytree.to_json)
  res_familytree = Org::Familysearch::Ws::Familytree::V2::Schema::FamilyTree.from_json JSON.parse(response.body)
  person = res_familytree.persons.first
  return person
end

#search(search_params) ⇒ Object

Params

search_params - A hash of search parameters matching API doc



92
93
94
95
96
97
98
99
100
# File 'lib/ruby-fs-stack/familytree/communicator.rb', line 92

def search(search_params)
  url = Base + 'search'
  url += add_querystring(search_params)
  response = @fs_communicator.get(url)
  familytree = Org::Familysearch::Ws::Familytree::V2::Schema::FamilyTree.from_json JSON.parse(response.body)
  # require 'pp'
  # pp familytree
  familytree.searches[0]
end

#write_note(options) ⇒ Object

Writes a note attached to the value ID of the specific person or relationship.

Params

  • options - Options for the note including the following:

    • :personId - the person ID if attaching to a person assertion.

    • :spouseIds - an Array of spouse IDs if creating a note attached to a spouse relationship assertion.

    • :parentIds - an Array of parent IDs if creating a note attached to a parent relationship assertion. If creating a note for a child-parent or parent-child relationship, you will need only one parent ID in the array along with a :childId option.

    • :childId - a child ID.

    • :text - the text of the note (required).

    • :assertionId - the valueId of the assertion you are attaching this note to.



233
234
235
236
237
238
239
240
241
242
# File 'lib/ruby-fs-stack/familytree/communicator.rb', line 233

def write_note(options)
  url = "#{Base}note"
  note = Org::Familysearch::Ws::Familytree::V2::Schema::Note.new
  note.build(options)
  familytree = Org::Familysearch::Ws::Familytree::V2::Schema::FamilyTree.new
  familytree.notes = [note]
  res = @fs_communicator.post(url,familytree.to_json)
  familytree = Org::Familysearch::Ws::Familytree::V2::Schema::FamilyTree.from_json JSON.parse(res.body)
  return familytree.notes.first
end

#write_relationship(base_id, options) ⇒ Object

Params

  • base_id - The root person for creating the relationship

  • options - Should include either :parent, :spouse, or :child. :lineage and :event is optional

:lineage can be set to the following values:

  • ‘Biological’

  • ‘Adoptive’

  • ‘Foster’

  • ‘Guardianship’

  • ‘Step’

  • ‘Other’

:event should be a hash with the following values ** :type - “Marriage”, etc. (REQUIRED) ** :place - “Utah, United States” (optional) ** :date - “Nov 2009”

:ordinance should be a hash with the following values ** :type - “Sealing_to_Spouse”, etc. (REQUIRED) ** :place - “Utah, United States” (optional) ** :date - “Nov 2009” ** :temple - ‘SLAKE’

If the :lineage is set, the parent-child relationships will be written via a characteristic. Otherwise, an exists assertion will be created to just establish the relationship.

Example

communicator.familytree_v2.write_relationship 'KWQS-BBQ', :parent => 'KWQS-BBT', :lineage => 'Biological' 
communicator.familytree_v2.write_relationship 'KWQS-BBQ', :parent => 'KWQS-BBT', :lineage => 'Adoptive'
communicator.familytree_v2.write_relationship 'KWQS-BBQ', :spouse => 'KWRT-BBZ', :event => {:type => 'Marriage', :date => '15 Aug 1987', :place => 'Utah, United States'}


156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
# File 'lib/ruby-fs-stack/familytree/communicator.rb', line 156

def write_relationship(base_id,options)
  
  relationship_type = get_relationship_type(options)
  with_id = options[relationship_type.to_sym]

  # Get the existing person/relationship or create a new person
  unless person = relationship(base_id,options.merge({:events => 'none'}))
    person = Org::Familysearch::Ws::Familytree::V2::Schema::Person.new
    person.id = base_id
  end
  
  # Add the relationship to the person with all of the correct options
  r_options = {:type => relationship_type, :with => with_id}
  r_options[:event] = options[:event] if options[:event]
  r_options[:ordinance] = options[:ordinance] if options[:ordinance]
  r_options[:lineage] = options[:lineage] if options[:lineage]
  person.create_relationship r_options
  
  # Create the payload
  familytree = Org::Familysearch::Ws::Familytree::V2::Schema::FamilyTree.new
  familytree.persons = [person]
  
  # Get the most current related ID for the URI
  rels = person.relationships.get_relationships_of_type(r_options[:type])
  rel = rels.find{|r|r.id == r_options[:with] || r.requestedId == r_options[:with]}
  related_id = rel.id
  url = "#{Base}person/#{base_id}/#{relationship_type}/#{related_id}"
  
  # Post the response and return the resulting person/relationship record from response
  response = @fs_communicator.post(url,familytree.to_json)
  res_familytree = Org::Familysearch::Ws::Familytree::V2::Schema::FamilyTree.from_json JSON.parse(response.body)
  person = res_familytree.persons.first
  return person 
end