Integrations / Frameworks / Rails / Working with Relationships
Feb. 27, 2019

Working with Relationships

Serializing relationships

You can easily embed nested objects defining an extra attribute returning any JSON-compliant object (an array or a hash or a combination of both).

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
class Profile < ActiveRecord::Base
  include AlgoliaSearch

  belongs_to :user
  has_many :specializations

  algoliasearch do
    attribute :user do
      # restrict the nested "user" object to its `name` + `email`
      { name: user.name, email: user.email }
    end
    attribute :public_specializations do
      # build an array of public specialization (include only `title` and `another_attr`)
      specializations.select { |s| s.public? }.map do |s|
        { title: s.title, another_attr: s.another_attr }
      end
    end
  end

end

Propagating change from a nested relation

With ActiveRecord

With ActiveRecord, we’ll be using touch and after_touch to achieve this.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
# app/models/app.rb
class App < ApplicationRecord
  include AlgoliaSearch

  belongs_to :author, class_name: :User
  after_touch :index!

  algoliasearch do
    attribute :title
    attribute :author do
      author.as_json
    end
  end
end

# app/models/user.rb
class User < ApplicationRecord
  # If your association uses belongs_to
  # - use `touch: true`
  # - do not define an `after_save` hook
  has_many :apps, foreign_key: :author_id

  after_save { apps.each(&:touch) }
end

With Sequel

With Sequel, you can use the touch plugin to propagate the changes:

1
2
3
4
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
# app/models/app.rb
class App < Sequel::Model
  include AlgoliaSearch

  many_to_one :author, class: :User

  plugin :timestamps
  plugin :touch

  algoliasearch do
    attribute :title
    attribute :author do
      author.to_hash
    end
  end
end

# app/models/user.rb
class User < Sequel::Model
  one_to_many :apps, key: :author_id

  plugin :timestamps
  # Can't use the associations since it won't trigger the after_save
  plugin :touch

  # Define the associations that need to be touched here
  # Less performant, but allows for the after_save hook to trigger
  def touch_associations
    apps.map(&:touch)
  end

  def touch
    super
    touch_associations
  end
end

Did you find this page helpful?