Module: ActionKitApi::Searchable

Included in:
Action, Event, EventCampaign, Page, User
Defined in:
lib/action_kit_api/searchable.rb

Class Method Summary collapse

Class Method Details

.included(class_name) ⇒ Object

This layer is needed to have the methods added at a class level rather than an instance level



5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
# File 'lib/action_kit_api/searchable.rb', line 5

def self.included(class_name)

  # Override's method missing to dynamically add find_by_* and
  # find_all_by_*.
  def class_name.method_missing(method, *args, &block)
    case method.to_s
      when /^find_by_(.+)$/
        run_find_by_method($1, *args)
      when /^find_all_by_(.+)$/
        run_find_all_by_method($1, *args, &block)
    else
      super
    end
  end

  # Perform an API search for an individual object
  def class_name.run_find_by_method(attrs, *args)
    # Get the name of the class that this module has been mixed into
    class_name = self.to_s.split("::").last

    search = self.parse_attributes(attrs, args)

    begin
      response = ActionKitApi.connection.call("#{class_name}.get", search)
    rescue XMLRPC::FaultException => exception
      if exception.faultCode == "DoesNotExist"
        return nil
      else
        raise exception
      end
    end

    # Build a new object with the response, this might be an empty
    # object if the search failed or was invalid
    self.new(response)
  end

  # Perform an API search for all objects that match the criteria, remote
  # API limit is 1000 results per request so this is added explicitely to
  # the call to prevent errors, in the future this request probably could
  # be paginated in a loop and using count to get all of the results that
  # match.
  def class_name.run_find_all_by_method(attrs, *args, &block)
    # Get the name of the class that this module has been mixed into
    class_name = self.to_s.split("::").last

    search = self.parse_attributes(attrs, args)
    
    # For when I get to retrieving all results, through pagination
    # Would be a good candidate for yielding (probably in batches of 50-100)
    #response_count = self.count(search)
    search["limit"] = 1000
    #search["offset"] = 0

    response = ActionKitApi.connection.call("#{class_name}.get", search)

    response_objects = []
    response.each do |obj|
      response_objects << self.new(obj)
    end

    response_objects
  end

  def class_name.count(search)
    ActionKitApi.connection.call("#{class_name}.count", search)
  end

  # Helper method for method_missing and the find_* virtual methods that
  # parses part of a method name and arguments into a hash usuable for the
  # API calls
  def class_name.parse_attributes(attrs, args)
    attrs = attrs.split('_and_')
    attrs_with_args = attrs.zip(args)
    Hash[attrs_with_args]
  end

  # Provide a means to check if the searchable module can respond to
  # virtual methods, could be more accurate by checking to ensure the
  # attributes exist
  def class_name.respond_to?(method)
    case method.to_s
      when /^find_by_(.*)$/
        true
      when /^find_all_by_(.*)$/
        true
    else
      super
    end
  end
end