module Protobuf::ActiveRecord::Scope::ClassMethods

Public Instance Methods

field_scope(field, options = {}) click to toggle source

Define fields that should be searchable via `search_scope`. Accepts a protobuf field and an already defined scope. If no scope is specified, the scope will be the field name, prefixed with `by_` (e.g. when the field is :guid, the scope will be :by_guid).

Optionally, a parser can be provided that will be called, passing the field value as an argument. This allows custom data parsers to be used so that they don't have to be handled by scopes. Parsers can be procs, lambdas, or symbolized method names and must accept the value of the field as a parameter.

Examples:

class User < ActiveRecord::Base
  scope :by_guid, lambda { |*guids| where(:guid => guids) }
  scope :custom_guid_scope, lambda { |*guids| where(:guid => guids) }

  # Equivalent to `field_scope :guid, :by_guid`
  field_scope :guid

  # With a custom scope
  field_scope :guid, :scope => :custom_guid_scope

  # With a custom parser that converts the value to an integer
  field_scope :guid, :scope => :custom_guid_scope, :parser => lambda { |value| value.to_i }
end
# File lib/protobuf/active_record/scope.rb, line 43
def field_scope(field, options = {})
  scope_name = if options.include?(:scope)
                 options[:scope]
               else
                 # When no scope is defined, assume the scope is the field, prefixed with `by_`
                 :"by_#{field}"
               end
  searchable_fields[field] = scope_name

  searchable_field_parsers[field] = options[:parser] if options[:parser]
end
for_upsert(proto) click to toggle source
# File lib/protobuf/active_record/scope.rb, line 159
def for_upsert(proto)
  valid_upsert = upsert_keys.find do |upsert_key|
    upsert_key.all? do |field|
      proto.respond_to_and_has_and_present?(field)
    end
  end

  fail UpsertNotFoundError unless valid_upsert.present?

  upsert_scope = model_scope
  valid_upsert.each do |field|
    value = proto.__send__(field)
    upsert_scope = upsert_scope.__send__(searchable_fields[field], value)
  end

  upsert_scope.first_or_initialize
end
model_scope() click to toggle source

Get an ARel relation to build off of. If we're in Rails 4 we need to use `all` instead of `scoped`. :noapi:

# File lib/protobuf/active_record/scope.rb, line 58
def model_scope
  ::ActiveRecord::VERSION::MAJOR >= 4 ? all : scoped
end
parse_search_values(proto, field) click to toggle source

:noapi:

# File lib/protobuf/active_record/scope.rb, line 63
def parse_search_values(proto, field)
  value = proto.__send__(field)

  if searchable_field_parsers[field]
    parser = searchable_field_parsers[field]

    if parser.respond_to?(:to_sym)
      value = self.__send__(parser.to_sym, value)
    else
      value = parser.call(value)
    end
  end

  values = [value].flatten
  values.map!(&:to_i) if proto.class.get_field(field, true).enum?
  values
end
search_scope(proto) click to toggle source

Builds and returns a Arel relation based on the fields that are present in the given protobuf message using the searchable fields to determine what scopes to use. Provides several aliases for variety.

Examples:

# Search starting with the default scope and searchable fields
User.search_scope(request)
User.by_fields(request)
User.scope_from_proto(request)
# File lib/protobuf/active_record/scope.rb, line 92
def search_scope(proto)
  search_relation = model_scope

  searchable_fields.each do |field, scope_name|
    next unless proto.respond_to_and_has_and_present?(field)

    search_values = parse_search_values(proto, field)
    search_relation = search_relation.__send__(scope_name, *search_values)
  end

  return search_relation
end
searchable_field_parsers() click to toggle source

:noapi:

# File lib/protobuf/active_record/scope.rb, line 111
def searchable_field_parsers
  @_searchable_field_parsers ||= {}
end
searchable_fields() click to toggle source

:noapi:

# File lib/protobuf/active_record/scope.rb, line 106
def searchable_fields
  @_searchable_fields ||= {}
end
upsert(proto) click to toggle source
# File lib/protobuf/active_record/scope.rb, line 177
def upsert(proto)
  record = for_upsert(proto)
  record.assign_attributes(proto)
  record.save
  record
end
upsert!(proto) click to toggle source
# File lib/protobuf/active_record/scope.rb, line 184
def upsert!(proto)
  record = for_upsert(proto)
  record.assign_attributes(proto)
  record.save!
  record
end
upsert_key(*fields) click to toggle source

Defines a scope that is eligible for upsert. The scope will be used to initialize a record with first_or_initialize. An upsert scope declariation must specify one or more fields that are required to be present on the request and also must have a field_scope defined.

If multiple upsert scopes are specified, they will be searched in the order they are declared for the first valid scope.

Examples:

class User < ActiveRecord::Base
  scope :by_guid, lambda { |*guids| where(:guid => guids) }
  scope :by_external_guid, lambda { |*external_guids|
    where(:external_guid => exteranl_guids)
  }
  scope :by_client_guid, lambda { |*client_guids|
    joins(:client).where(
      :clients => { :guid => client_guids }
     )
  }

  field_scope :guid
  field_scope :client_guid
  field_scope :external_guid

  upsert_scope :external_guid, :client_guid
  upsert_scope :guid

end
# File lib/protobuf/active_record/scope.rb, line 145
def upsert_key(*fields)
  fields = fields.flatten

  fields.each do |field|
    fail UpsertScopeError unless searchable_fields[field].present?
  end

  upsert_keys << fields
end
upsert_keys() click to toggle source
# File lib/protobuf/active_record/scope.rb, line 155
def upsert_keys
  @_upsert_keys ||= []
end