Module: ActiveStash::Search

Defined in:
lib/active_stash/search.rb

Overview

ActiveStash

Provides encrypted index and search for ActiveRecord models that have encrypted fields.

(Re)indexing

To index your encrypted data into CipherStash, use the reindex task:

rake active_stash:reindexall

If you want to just reindex one model, for example `User`, run:

active_stash:reindex[User]

You can also reindex in code:

User.reindex

Depending on how much data you have, reindexing may take a while but you only need to do it once. *ActiveStash will automatically index (and delete) data as it records are created, updated and deleted.*

Running Queries

To perform queries over your encrypted records, you can use the `query` method For example, to find a user by email address:

User.query(email: "person@example.com")

This will return an ActiveStash::Relation which extends `ActiveRecord::Relation` so you can chain most methods as you normally would!

To constrain by multiple fields, include them in the hash:

User.query(email: "person@example.com", verified: true)

You can perform a free-text search over all strings in the model by passing the query string as the first argument:

User.query("exam")

To order by `dob`, do:

User.query(email: "person@example.com).order(:dob)

You can even order by strings:

User.query(verified: true).order(:first_name)

Or to use limit and offset:

User.query(verified: true).limit(10).offset(20)

This means that `ActiveStash` should work with pagination libraries like Kaminari.

You also, don't have to provide any constraints at all and just use the encrypted indexes for ordering! To order all records by `dob` descending and then `created_at`, do:

User.order(dob: :desc, :created_at)

Advanced Queries

More advanced queries can be performed by passing a block to query. For example, to find all users born in or after 1998:

User.query { |q| q.dob > "1998-01-01".to_date }

Or, to perform a free-text search on name:

User.query { |q| q.name =~ "Dan" }

To combine multiple constraints, make multiple calls in the block:

User.query do |q|
  q.dob > "1998-01-01".to_date
  q.name =~ "Dan"
end

To perform a free-text search with additional constraints:

User.query("myquery") do |q|
  q.dob > "1998-01-01".to_date
end

Defined Under Namespace

Modules: ClassMethods

Class Method Summary collapse

Instance Method Summary collapse

Class Method Details

.included(base) ⇒ Object



86
87
88
89
90
91
92
93
94
# File 'lib/active_stash/search.rb', line 86

def self.included(base)
  base.extend ClassMethods

  base.class_eval do
    before_save :ensure_stash_id
    after_save :cs_put
    after_destroy :cs_delete
  end
end

Instance Method Details

#cs_deleteObject

Delete the current record from the CipherStash index



119
120
121
# File 'lib/active_stash/search.rb', line 119

def cs_delete
  self.class.collection.delete(self.stash_id)
end

#cs_putObject

Index this record into CipherStash



97
98
99
100
101
102
103
104
105
106
107
108
# File 'lib/active_stash/search.rb', line 97

def cs_put
  ActiveStash::Logger.info("Indexing #{self.stash_id}")
  ensure_stash_id

  # TODO: If this fails, throw :abort
  # it should unset stash_id if this record did not already exist
  # Note: It turns out that Lockbox doesn't support serializable_hash
  self.class.collection.upsert(
    self.stash_id,
    self.stash_attrs
  )
end

#stash_attrsObject



110
111
112
113
114
115
116
# File 'lib/active_stash/search.rb', line 110

def stash_attrs
  indexed_fields = self.class.stash_indexes.indexes.map(&:field).uniq

  self.attributes.select do |k, v|
    indexed_fields.include?(k)
  end
end