> ## Documentation Index
> Fetch the complete documentation index at: https://algolia.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Upgrade the Ruby API client to version 2

> Keep your Ruby API client up to date to benefit from improvements and bug fixes.

export const Legacy = ({title, href}) => {
  return <Note>

    This page documents an earlier version of the API client.
    For the latest version, see <a href={href}>{title}</a>.

    </Note>;
};

<Legacy title="Upgrade" href="/doc/libraries/sdk/upgrade/ruby" />

The Ruby API client follows [semantic versioning](http://semver.org).

## Upgrade from version 1 to version 2

The Ruby client is fully rebuilt while keeping a similar design to make it as smooth as possible to upgrade.
It's compatible with Ruby 2.2 and later.

## Upgrade the library

In your `Gemfile`, replace the `algoliasearch` gem with the `algolia` gem.

```sh Command line icon=square-terminal theme={"system"}
gem 'algoliasearch' # [!code --]
gem 'algolia'  # [!code ++]
```

Then, run the following command to install all dependencies:

```sh Command line icon=square-terminal theme={"system"}
bundle install
```

## Class names

Most classes have a different name and namespace in the new version.
The most used classes are now as follows:

* `Algolia::Client` → `Algolia::Search::Client`
* `Algolia::Index` → `Algolia::Search::Index`
* `Algolia::AccountClient` → `Algolia::Account::Client`
* `Algolia::Analytics` → `Algolia::Analytics::Client`
* `Algolia::Insights` → `Algolia::Insights::Client`

## Client instantiation

There's a slight change in how you instantiate the client.
Index initialization remains the same:

```ruby Ruby icon=code theme={"system"}
# Before
client = Algolia::Client.new(
  application_id: "ALGOLIA_APPLICATION_ID",
  api_key: "ALGOLIA_API_KEY"
)
index = client.init_index("index_name")

# After - Option 1
client = Algolia::Search::Client.create("ALGOLIA_APPLICATION_ID", "ALGOLIA_API_KEY")
index = client.init_index("index_name")

# After - Option 2
search_config = Algolia::Search::Config.new(application_id: "ALGOLIA_APPLICATION_ID", api_key: "ALGOLIA_API_KEY")
client = Algolia::Search::Client.create_with_config(search_config)
index = client.init_index("index_name")
```

By default, the keys of the response hashes are symbols. If you want the keys to be strings instead of symbols, you can set the `symbolize_keys` configuration option to `false`:

```ruby Ruby icon=code theme={"system"}
search_config = Algolia::Search::Config.new(application_id: app_id, api_key: api_key, symbolize_keys: false)
client = Algolia::Search::Client.create_with_config(search_config)
```

### Instantiate with configuration

You can instantiate all clients using configuration objects.
This helps you change their default behavior and settings, such as the default region in the Insights client or custom hosts in the Search client.
All setters have been moved from the client to the configuration object. If, for instance, you rely on the [`set_extra_headers`](/doc/libraries/sdk/v1/methods/set-extra-header) method or have [configured timeouts](/doc/libraries/sdk/v1/methods/configuring-timeouts) by passing options to the client during initialization, you need to change your code to use a configuration object.

For example:

```ruby Ruby icon=code theme={"system"}
# Before
Algolia.set_extra_header("NAME-OF-HEADER", "value")
client = Algolia::Client.new(
  {
    application_id: "ALGOLIA_APPLICATION_ID",
    api_key: "ALGOLIA_API_KEY",
    connect_timeout: 2,
    receive_timeout: 10
  }
)

# After
search_config = Algolia::Search::Config.new(
  application_id: "ALGOLIA_APPLICATION_ID",
  api_key: "ALGOLIA_API_KEY",
  read_timeout: 10,
  connect_timeout: 2
)
search_config.set_extra_header("NAME-OF-HEADER", "value")

client = Algolia::Search::Client.create_with_config(search_config)
```

## Optional parameters

To have the most consistent, predictable, and future-proof method signatures, methods follow two rules:

* All required parameters have a single argument each
* All optional arguments are part of a hash called `opts` as the last argument

Most method names remain the same, just the arguments have changed.
Typically, optional parameters have been removed,
which you must now pass in the `opts` hash.
The same goes for any `search_parameters` and `request_options` arguments.

For example:

```ruby Ruby icon=code theme={"system"}
# Before
request_opts = {:"X-Algolia-UserToken" => "user123"}
search_params = {hitsPerPage: 50}

index.search("query", search_params, request_opts)

# After
opts = {
  headers: {:"X-Algolia-UserToken" => "user123"},
  hitsPerPage: 50
}
index.search("query", opts)
```

Besides moving all optional parameters,
go through [all method changes](#list-of-method-changes) to see how they've changed.

## New methods

The new client introduces some new methods. Most of these are helper methods:
the underlying feature was already available, but required either deeper understanding or custom code.

* [`set_personalization_strategy`](/doc/libraries/sdk/v1/methods/add-strategy): set the Personalization strategy for an index.
* [`get_personalization_strategy`](/doc/libraries/sdk/v1/methods/get-strategy): get the Personalization strategy for an index.
* [`Algolia::Account::Client.copy_index`](/doc/libraries/sdk/v1/methods/copy-index#copy-index-between-apps): copy in an index between Algolia applications.

## List of method changes

### `Client` methods

#### `multiple_queries`

The `strategy` parameter is no longer a string, but a key in the `opts`.

```ruby Ruby icon=code theme={"system"}
queries = [
  {indexName: "index_name1", params: {query: "query", hitsPerPage: 2}},
  {indexName: "index_name2", params: {query: "another_query", hitsPerPage: 5}}
]

# Before
client.multiple_queries(queries, "stopIfEnoughMatches")

# After
client.multiple_queries(queries, {strategy: "stopIfEnoughMatches"})
```

#### `generate_secured_api_key`

This method moved to the `Algolia::Search::Client` class.

```ruby Ruby icon=code theme={"system"}
# Before
secured_api_key = Algolia.generate_secured_api_key(
  "api_key",
  {
    validUntil: now - (10 * 60)
  }
)

# After
secured_api_key = Algolia::Search::Client.generate_secured_api_key(
  "api_key",
  {
    validUntil: now - (10 * 60)
  }
)
```

#### `add_api_key`

`acl` is now a single parameter.
The other parameters have been moved to the `opts`.

```ruby Ruby icon=code theme={"system"}
# Before
client.add_api_key({acl: ["search"], description: "A description", indexes: ["index"]})

# After
client.add_api_key(
  ["search"],
  {
    description: "A description",
    indexes: ["index"]
  }
)
```

#### `update_api_key`

This method is now a member of the `Algolia::Search::Client` class.

```ruby Ruby icon=code theme={"system"}
# Before
Algolia.update_api_key("api_key", {maxHitsPerQuery: 42})

# After
client.update_api_key("api_key", {maxHitsPerQuery: 42})
```

#### `get_secured_api_key_remaining_validity`

This method moved to the `Algolia::Search::Client` class.

```ruby Ruby icon=code theme={"system"}
# Before
Algolia.get_secured_api_key_remaining_validity("api_key")

# After
Algolia::Search::Client.get_secured_api_key_remaining_validity("api_key")
```

#### `list_user_ids`

The `page` and `hitsPerPage` parameters are now part of the `opts` hash.

```ruby Ruby icon=code theme={"system"}
# Before
page = 0
hits_per_page = 20
client.list_user_ids(page, hits_per_page)

# After
client.list_user_ids({hitsPerPage: 20, page: 0})
```

#### `search_user_ids`

The `clusterName`, `page`, and `hitsPerPage` parameters are now part of the `opts` hash.

```ruby Ruby icon=code theme={"system"}
# Before
page = 0
hits_per_page = 12
client.search_user_ids("query", "my-cluster", page, hits_per_page)

# After
client.search_user_ids("query", {clusterName: "my-cluster", hitsPerPage: 12, page: 0})
```

#### `get_logs`

The `offset`, `length`, and `type` parameters are now part of the `opts` hash.

```ruby Ruby icon=code theme={"system"}
# Before
offset = 5
length = 100
puts(client.get_logs(offset, length, "all"))

# After
client.get_logs({offset: 5, length: 10, type: "all"})
```

### `Index` methods

#### `search`

`searchParameters` and `opts` are combined in a single parameter.

```ruby Ruby icon=code theme={"system"}
# Before
request_opts = {:"X-Algolia-UserToken" => "user123"}
search_params = {hitsPerPage: 50}

index.search("query", search_params, request_opts)

# After
opts = {
  headers: {:"X-Algolia-UserToken" => "user123"},
  hitsPerPage: 50
}
index.search("query", opts)
```

#### `search_for_facet_values`

`searchParameters` and `opts` are combined in a single parameter.

```ruby Ruby icon=code theme={"system"}
# Before
request_opts = {:"X-Algolia-UserToken" => "user123"}
search_params = {hitsPerPage: 50}

index.search_for_facet_values("category", "phone", search_params, request_opts)

# After
opts = {
  headers: {:"X-Algolia-UserToken" => "user123"},
  hitsPerPage: 50
}
index.search_for_facet_values("category", "phone", opts)
```

#### `find_object`

The method takes a lambda, proc, or block as the first argument (anything that responds to `call`),
and the `opts` as the second.

```ruby Ruby icon=code theme={"system"}
# Before
index.find_object({query: "query", paginate: true}) { |hit| hit[:title].include?("algolia") }

# After
index.find_object(-> (hit) { hit[:title].include?("algolia") }, {query: "query", paginate: true})
```

#### `get_object_position`

The class name has changed, but the method remains the same.

```ruby Ruby icon=code theme={"system"}
# Before
position = Algolia::Index.get_object_position(results, "object")

# After
position = Algolia::Search::Index.get_object_position(results, "object")
```

#### `add_object` and `add_objects`

These methods are removed in favor of [`save_object` and `save_objects`](/doc/libraries/sdk/v1/methods/save-objects).

#### `partial_update_object`

The `createIfNotExists` flag is now part of the `opts` parameter.
It defaults to `false` in version 2.
(It was `true` in version 1.)

You only need to specify the `objectID` in the record to be updated,
not as an argument when using the method.
[`createIfNotExists`](/doc/libraries/sdk/v1/methods/partial-update-objects#param-create-if-not-exists) is now part of the `opts` parameter.

```ruby Ruby icon=code theme={"system"}
obj = {objectID: "1234", prop: "value"}

# Before
create_if_not_exists = true
index.partial_update_object(obj, obj[:objectID], create_if_not_exists)

# After
index.partial_update_object(obj, {createIfNotExists: true})
```

#### `partial_update_objects`

The `createIfNotExists` flag is now part of the `opts` parameter.
It defaults to `false` in version 2.
(It was `true` in version 1.)

```ruby Ruby icon=code theme={"system"}
# Before
create_if_not_exists = true
index.partial_update_objects(objects, create_if_not_exists)

# After
index.partial_update_objects(objects, {createIfNotExists: true})
```

#### `clear_index`

Renamed to `clear_objects`.

```ruby Ruby icon=code theme={"system"}
# Before
index.clear_index

# After
index.clear_objects
```

#### `get_object` and `get_objects`

The `attributesToRetrieve` parameter is now part of the `opts`.

```ruby Ruby icon=code theme={"system"}
# Before
index.get_object("1234", ["title"])
index.get_objects([1, 2, 3], ["title"])

# After
index.get_object("1234", {attributesToRetrieve: ["title"]})
index.get_objects([1, 2, 3], {attributesToRetrieve: ["title"]})
```

#### `delete_index`

Instead of calling the `delete_index` method on the client,
you should call the `delete` method directly on the index object.

```ruby Ruby icon=code theme={"system"}
# Before
client.delete_index("foo")

# After
index.delete
```

#### `browse`

Renamed to `browse_objects`.

```ruby Ruby icon=code theme={"system"}
# Before
request_opts = {:"X-Algolia-UserToken" => "user123"}
index.browse({query: "query"}, nil, request_opts) do |hit|
  puts(hit)
end

# After
opts = {
  query: "query",
  headers: {:"X-Algolia-UserToken" => "user123"}
}
index.browse_objects(opts) do |hit|
  puts(hit)
end
```

#### `save_synonym`

You only need to specify the `objectID` in the synonym to be saved,
not as an argument when using the method.

```ruby Ruby icon=code theme={"system"}
# Before
forward_to_replicas = true
index.save_synonym("one", {objectID: "one", type: "synonym", synonyms: %w[one two]}, forward_to_replicas)

# After
index.save_synonym({objectID: "one", type: "synonym", synonyms: %w[one two]}, {forwardToReplicas: true})
```

#### `batch_synonyms`

Renamed to `save_synonyms`.
The [`forwardToReplicas`](/doc/libraries/sdk/v1/methods/save-synonym#param-forward-to-replicas) and [`replaceExistingSynonyms`](/doc/libraries/sdk/v1/methods/save-synonyms#param-replace-existing-synonyms) parameters are now part of the `opts` hash.

```ruby Ruby icon=code theme={"system"}
# Before
forward_to_replicas = true
replace_existing_synonyms = true
index.batch_synonyms(synonyms, forward_to_replicas, replace_existing_synonyms)
# After
index.save_synonyms(synonyms, {forwardToReplicas: true, replaceExistingSynonyms: true})
```

#### `export_synonyms`

Renamed to `browse_synonyms`.

```ruby Ruby icon=code theme={"system"}
# Before
synonyms = index.export_synonyms

# After
synonyms = index.browse_synonyms
```

#### `save_rule`

You only need to specify the `objectID` in the rule to be saved,
not as an argument when using the method.

```ruby Ruby icon=code theme={"system"}
# Before
index.save_rule(
  "unique-id",
  {
    objectID: "unique-id",
    conditions: [{anchoring: "is", pattern: "pattern"}],
    consequence: {
      params: {
        query: {
          edits: [
            {type: "remove", delete: "pattern"}
          ]
        }
      }
    }
  }
)

# After
index.save_rule(
  {
    objectID: "unique-id",
    conditions: [{anchoring: "is", pattern: "pattern"}],
    consequence: {
      params: {
        query: {
          edits: [
            {type: "remove", delete: "pattern"}
          ]
        }
      }
    }
  }
)
```

#### `batch_rules`

Renamed to `save_rules`.
The [`forwardToReplicas`](/doc/libraries/sdk/v1/methods/save-rule#param-forward-to-replicas) and [`clearExistingRules`](/doc/libraries/sdk/v1/methods/batch-rules#param-clear-existing-rules) parameters should now be part of the `opts`.

```ruby Ruby icon=code theme={"system"}
# Before
forward_to_replicas = true
clear_existing_rules = true
index.batch_rules(rules, forward_to_replicas, clear_existing_rules)

# After
index.save_rules(rules, {forwardToReplicas: true, clearExistingRules: true})
```

#### `delete_rule`

The [`forwardToReplicas`](/doc/libraries/sdk/v1/methods/delete-rule#param-forward-to-replicas) parameter is now part of the `opts`.

```ruby Ruby icon=code theme={"system"}
# Before
forward_to_replicas = true
index.delete_rule("rule-id", forward_to_replicas)

# After
index.delete_rule("rule-id", {forwardToReplicas: true})
```

#### `clear_rules`

The `forwardToReplicas` parameter is now part of the `opts`.

```ruby Ruby icon=code theme={"system"}
# Before
forward_to_replicas = true
index.clear_rules(forward_to_replicas)

# After
index.clear_rules({forwardToReplicas: true})
```

#### `export_rules`

Renamed to `browse_rules`.

```ruby Ruby icon=code theme={"system"}
# Before
index.export_rules

# After
index.browse_rules
```
