# Ruby v2.X

### Introduction

#### SDK overview

Welcome to the Flagship Ruby SDK documentation!

This article guides you through the steps to integrate Flagship with your Ruby applications using our client library with pre-configured methods to utilize the Decision API.

#### SDK features

This SDK version enables you to:

* Set a [visitor ID](doc:glossary#visitor-id)
* Update [user context](doc:glossary#user-context)
* Assign campaigns via the [Decision API](doc:decision-api#campaigns) or [Bucketing](doc:bucketing)
* Retrieve modifications
* Activate campaigns
* Send hits to our [Universal Collect](doc:universal-collect-documentation)

#### Prerequisites

* **Ruby**: version 2.5.0 or later
* Your server/device must have access to the internet.
* You need the bundler gem in your Ruby environment.

#### Good to know

* Github repository: <https://github.com//flagship-io/flagship-ruby-sdk>
* Ruby code supported

### Getting Started

#### Installation

Our Ruby SDK is available on [rubygems.org](https://rubygems.org/). To install it, run the following command in your Ruby environment:

```shell
gem install flagship
```

You can also install the library from other sources by adding the following to your Gemfile:

```shell
gem 'flagship', :git => 'git://github.com/abtasty/flagship-ruby-sdk.git'
```

Then, run this command:

```shell
bundle install
```

#### Initialization

Once the library is installed in your Ruby environment, take your Ruby source file:

* First require the **Flagship**, **Config** class from **flagship** gem.
* Get the Flagship instance by calling **Flagship::Flagship.instance()**.
* Then call the **start()** method passing a **Config** object as parameter.

```ruby
require 'flagship'
```

## Start with default config

```ruby
Flagship::Flagship.instance.start("your_env_id", "your_api_key", Flagship::Config.new)
```

## Start in bucketing mode

```ruby
Flagship::Flagship.instance.start("your_env_id", "your_api_key", Flagship::Config.new(event_handler: t, mode: Flagship::Config::Mode::BUCKETING, polling_interval: 5, timeout: 0.1))
```

| Parameter | Type   | Description                                  |
| --------- | ------ | -------------------------------------------- |
| env\_id   | String | Environment id provided by Flagship.         |
| api\_key  | String | Api authentication key provided by Flagship. |
| config    | Config | configure the flagship SDK.                  |

> 📘 Info
>
> You can find your `api_key` and your `environment_id` on your Flagship account, in Parameters > Environment & Security. [**Find this ID**](doc:getting-started)

**Configuration**

The **Config** class lets you configure the SDK.

```ruby
require 'flagship'

class CustomEventHandler < Flagship::EventHandler  
  def initialize  
    super  
  end

  def on_log(level, message)  
    puts "Log >> #{message}"  
  end

  def on_exception_raised(exception, traceback)  
    super(exception, traceback)  
    puts "Exception >> #{exception}"  
  end  
end

Flagship::Flagship.instance.start("your_env_id", "your_api_key", Flagship::Config.new(event_handler: CustomEventHandler.new))
```

**`Config.new():`**

| Parameter         | Type             | Description                                                                                                                                                                                                                                                                                                                         |
| ----------------- | ---------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| mode              | Symbol           | Lets you start the Flagship SDK in `Flagship::Config::Mode::BUCKETING` mode (decision logic is executed sdk-side) or `Flagship::Config::Mode::DECISION_API` mode (decision logic is executed server-side). The decision mode is set to `Flagship::Config::Mode::DECISION_API` by default. [**Learn more**](#decision-mode)          |
| event\_handler    | EventHandler     | Custom `EventHandler` implementation to provide logs and error handling.                                                                                                                                                                                                                                                            |
| polling\_interval | Integer or Float | Bucketing polling interval in seconds. Default is 60 seconds. Min is 1 second. If <= 0 is given, polling will be disabled. In api mode, panic status will be updated at each call of synchronize\_modifications. In Bucketing mode, panic status will be updated at each polling interval, or at start time if polling is disabled. |
| timeout           | Integer or Float | set a custom timeout in seconds for campaign requests. Default is 2 seconds.                                                                                                                                                                                                                                                        |

**Decision Mode**

**`:DECISION_API`Mode**

When the SDK is running in `:DECISION_API` mode, the campaign assignments and targeting validation take place server-side. In this mode, each call to the `synchronize_modifications` method to refresh the modifications will create an HTTP request.

**`:BUCKETING`Mode**

When the SDK is running in `:BUCKETING` mode, the SDK downloads all the campaigns configurations at once in a single bucketing file so that variation assignment can be computed client-side by the SDK. This bucketing file is stored in cache and will only be downloaded again when campaign configurations are modified in the Flagship interface. It is possible to configure the interval of polling refresh with the polling\_interval configuration. [**Learn more**](doc:bucketing)

**Create a visitor**

The `visitor` instance is a helper object that lets you manage the context and campaigns for a user identified by a unique ID.

The user context is a property dataset that defines the current user of your app. This dataset is sent and used by the Flagship Decision API as targeting criteria for campaign assignment.

For example, if you want to enable or disable a specific feature based on VIP status, you would pass this attribute as a key-value pair in the user context so that the Decision API can enable or disable the corresponding feature flag for the user.

> 📘 Info
>
> User context values are used for targetings.

```ruby
context = {
	'isVipUser': true,
	'name': 'visitor',
	'age': 30
}

visitor = Flagship::instance.create_visitor("user_#1234", true, context) 
```

To create a new user use the method create\_visitor.

```ruby
def create_visitor(visitor_id, authenticated=false, context={})
```

| Parameter     | Type    | Description                                                                                                                                                                                                 |
| ------------- | ------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| visitor\_id   | String  | Unique identifier for the current user. This can be an ID from your database or a session ID. If no value is passed, the SDK will automatically generate a unique ID. [Learn more](doc:glossary#visitor-id) |
| authenticated | Boolean | Specify if the current visitor is authenticated or anonymous                                                                                                                                                |
| context       | Hash    | Optional. Hash of key-value pairs describing the user and device context. \[Learn more]\(                                                                                                                   |

> 🚧 Caution
>
> * User context keys must have a type of `str`
> * User context values must have a type of `str`, `bool`, `int`, or `float`

### Updating the user context

The user context is a property dataset that defines the current user of your app. This dataset is sent and used by the Flagship Decision API as targeting criteria for campaign assignment.

The following method from the `visitor` instance allows you to set new context values matching the given keys.

```ruby
context = {
	'isVipUser' => true,
	'name' => 'visitor',
	'age' => 30
}

visitor = Flagship::instance.create_visitor("user_#1234")

visitor.update_context(context)
visitor.update_context({'age' => 31}, true)
```

**`def update_context(self, context, synchronize=false)`**

| Parameter   | Type        | Description                                                                                                                                                                                                                                                                                                       |
| ----------- | ----------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| context     | Hash, array | Hash `{key: value}` or Array `[key, value]` describing the user and device context. [**Learn more**](doc:glossary#user-context)                                                                                                                                                                                   |
| synchronize | bool        | Optional. Set to `false` by default. If set to `true`, it will automatically call `synchronize_modifications()` and then update the modifications from the server for all campaigns in accordance with the latest user context. You can also update them manually at any time with `synchronize_modifications()`. |

> 🚧 Caution
>
> * User context keys must have a type of `str`
> * User context values must have a type of `str`, `bool`, `int`, or `float`

### Campaign synchronization

#### Synchronizing campaigns

The `synchronize_modifications()` method of the `Flagship::Visitor` instance automatically calls the Flagship Decision API to run campaign assignments according to the current user context and retrieve applicable modifications.

These modifications are then stored in the SDK and updated asynchronously when `synchronize_modifications()` is called.

You can also synchronize campaigns by passing `synchronize=true` parameter in the `update_context` function.

```ruby
visitor = Flagship::instance.create_visitor("user_#1234", true, {'isVip' => true})

#Synchronize by passing true to update context.
visitor.update_context({'age' => 31}, true)

#Synchronize with stand alone function
visitor.synchronize_modifications()
```

**`def synchronize_modifications()`**

Once the campaign has been **assigned** and **synchronized**, all the modifications are stored in the SDK. You can retrieve these modifications using the following functions from the `Flagship::Visitor` instance:

```ruby
visitor = Flagship::instance.create_visitor("user_#1234", true, {'isVip' => true})
visitor.synchronize_modifications()

vip_feature_enabled = visitor.get_modification('vip_feature', false)
```

**`def get_modification(self, key, default_value, activate=False)`**

| Parameter      | Type                              | Description                                                                                                                                                                                                                                    |
| -------------- | --------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| key            | str                               | Key associated with the modification.                                                                                                                                                                                                          |
| default\_value | int, bool, float, str, dict, list | Default value returned when the key does not match any modification value.                                                                                                                                                                     |
| activate       | bool                              | Optional. Set to `False` by default. Set this parameter to `True` to automatically report on our server that the current visitor has seen this modification. If `False`, call the [activate\_modification()](#activating-modifications) later. |

It returns the current modification or the default value.

#### Getting campaign information

You may need to send campaign IDs to a third-party for reporting and/or analytics purposes. It is now possible to retrieve **campaign IDs** for a specific modification key.

```ruby
visitor = Flagship::instance.create_visitor("visitor_id")
visitor.get_modification_info("modification_key")
```

**`fun get_modification_info(key: String) : dict`**

| Parameter | Type | Description                           |
| --------- | ---- | ------------------------------------- |
| key       | str  | Key associated with the modification. |

It returns a dictionary containing `campaignId`, `variationGroupId`, `variationId` and `isReference` values or none if the modification is not found (i.e. user does not belong to the campaign).

#### Activating modifications

Once a modification is displayed on the screen for a user, you must send an activate event to tell Flagship that the user has seen this specific variation.

There are two options for activating a modification:

1. Pass an `activate=True` parameter to the **get\_modification()** function
2. Use the following **activate\_modification()** method from the Flagship::Visitor instance.

```ruby
visitor = Flagship::instance.create_visitor("user_#1234", True, {'isVip' => True})
visitor.synchronize_modifications()

#Activation during get_modification
vip_feature_enabled = visitor.get_modification('vip_feature', True)

#Activation from stand alone activate_modification
menu_order = visitor.get_modification('menu_order', False)
visitor.activate_modification('menu_order')
```

**`def activate_modification(self, key)`**

| Parameter | Type | Description                           |
| --------- | ---- | ------------------------------------- |
| key       | str  | Key associated with the modification. |

### Experience Continuity

Dealing with anonymous and logged-in users, experience continuity allows you to maintain consistency between sessions and devices.

> 🚧
>
> Make sure that the experience continuity option is enabled on the flagship platform before using those methods.

#### Authenticate

**`def authenticate(visitor_id, context=nil, synchronize=false)`**

| Parameter   | Type   | Description                                                                                                                                                                   |
| ----------- | ------ | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| visitor\_id | string | new ID of the new authenticated visitor.                                                                                                                                      |
| context     | hash   | (optional) Replace the current visitor context. Passing nil won't replace context and will ensure consistency with the previous visitor context.                              |
| synchronize | bool   | (optional) if true, the SDK will automatically update the campaign's modifications. You also have the possibility to update it manually by calling synchronizeModifications() |

#### Unauthenticate

**`def unauthenticate(context=nil, synchronize=false)`**

| Parameter   | Type | Description                                                                                                                                                        |
| ----------- | ---- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| context     | hash | (optional) Replace the current visitor context. Passing nil won't replace context and will ensure consistency with the previous visitor context.                   |
| synchronize | bool | if true, the SDK will automatically update the campaign's modifications. You also have the possibility to update it manually by calling synchronizeModifications() |

#### Code example

```ruby
# When visitor log in.
visitor.authenticate("new_visitor_id")

# When visitor log out.
visitor.unauthenticate()
```

### Hit Tracking

This section helps you track your users in your application and learn how to build hits in order to feed campaign goals. For more information about our measurement protocol, read our [Universal Collect documentation](doc:universal-collect-documentation).

There are four different types of Hits available:

* Page
* Transaction
* Item
* Event

**They must all be built and sent with the following method from the`visitor` instance:**

**`def send_hit(hit)`**

#### Common parameters

```ruby
visitor.send_hit(Flagship::Page.new("https://www.mydomain.com/page")
                            .with_ip("133.3.223.1")
                            .with_locale("fr-fr")
                            .with_resolution(640, 480)
                            .with_session_number(3))
```

| Parameter               | Type  | Description                         |
| ----------------------- | ----- | ----------------------------------- |
| userIp                  | str   | Optional. User IP                   |
| screenResolution        | str   | Optional. Screen resolution.        |
| userLanguage            | str   | Optional. User language             |
| currentSessionTimeStamp | int64 | Optional. Current Session Timestamp |
| sessionNumber           | int   | Optional. Session number            |

#### Page

This hit should be sent each time a visitor arrives on a new page on the server-side.

```ruby
visitor.send_hit(Flagship::Page.new("https://www.mydomain.com/page"))
```

**`Page.initialize(location):`**

| Builder Parameter | Type | Description          |
| ----------------- | ---- | -------------------- |
| location          | str  | Required. valid URL. |

#### Screen

This hit should be sent each time a visitor arrives on an interface on the client-side.

```ruby
visitor.send_hit(Flagship::Screen.new("ruby_interface_name"))
```

**`Screen.initialize(location):`**

| Builder Parameter | Type | Description               |
| ----------------- | ---- | ------------------------- |
| location          | str  | Required. Interface name. |

#### Transaction

This hit should be sent when a user completes a Transaction.

```ruby
visitor.send_hit(Flagship::Transaction.new("#309830", "purchases")
                     .with_currency("EUR")
                     .with_item_count(3)
                     .with_payment_method("cb")
                     .with_shipping_cost(4.99)
                     .with_shipping_method("1d")
                     .with_taxes(9.99)
                     .with_total_revenue(420.00)
                     .with_coupon_code("#SAVE10"))
```

**`Transaction.initialize(transaction_id, affiliation)`**

| Builder Parameter | Type | Description                                                                                                |
| ----------------- | ---- | ---------------------------------------------------------------------------------------------------------- |
| transaction\_id   | str  | Required. Unique identifier for your transaction.                                                          |
| affiliation       | str  | Required. The name of the KPI that you will have inside your reporting. [**Learn more**](doc:glossary#kpi) |

Methods are provided to set the following values:

| Builder Parameter  | Type  | Description                                                                                                                       |
| ------------------ | ----- | --------------------------------------------------------------------------------------------------------------------------------- |
| totalRevenue       | float | Optional. Specifies the total revenue associated with the transaction. This value should include any shipping and/or tax amounts. |
| shippingCost       | float | Optional. The total shipping cost of your transaction.                                                                            |
| withShippingMethod | str   | Optional. The shipping method for your transaction.                                                                               |
| taxes              | float | Optional. Specifies the total amount of taxes in your transaction.                                                                |
| currency           | str   | Optional. Specifies the currency of your transaction. NOTE: This value should be a valid ISO 4217 currency code.                  |
| paymentMethod      | str   | Optional. Specifies the payment method used for your transaction.                                                                 |
| itemCount          | int   | Optional. Specifies the number of items in your transaction.                                                                      |
| couponCode         | str   | Optional. Specifies the coupon code used by the customer in your transaction.                                                     |

#### Item

This hit is used to link an item with a transaction. It must be sent after the corresponding transaction hit.

```ruby
visitor.send_hit(Flagship::Item.new("#309830", "ATX2080", "cg_atx_20802020")
                     .with_item_category("hardware")
                     .with_item_quantity(2)
                     .with_price(210.00))
```

**`Item.initialize(transaction_id, product_name, productSku)`**

| Builder Parameter | Type | Description                                       |
| ----------------- | ---- | ------------------------------------------------- |
| transaction\_id   | str  | Required. Unique identifier for your transaction. |
| product\_name     | str  | Required. The name of your item.                  |
| product\_sku      | str  | Specifies the SKU or item code.                   |

Methods are provided to set the following values:

| Builder Parameter | Type  | Description                                                |
| ----------------- | ----- | ---------------------------------------------------------- |
| price             | float | Optional. Specifies the price for a single item/unit.      |
| itemCategory      | str   | Optional. Specifies the category that the item belongs to. |
| itemQuantity      | int   | Optional. Specifies the number of items purchased.         |

> 📘 Info
>
> The `Item` hit isn't available yet in the Flagship reporting view.

#### Event

This hit can be used for any event (e.g. Add To Cart click, newsletter subscription).

```ruby
visitor.send_hit(Flagship::Event.new(Flagship::EventCategory::USER_ENGAGEMENT, "click_basket")
                     .with_event_label('basket button')
                     .with_event_value(420))
```

**`Flagship::Event.initialize(category, action)`**

| Builder Parameter | Type                    | Description                                                                                                                       |
| ----------------- | ----------------------- | --------------------------------------------------------------------------------------------------------------------------------- |
| category          | Flagship::EventCategory | Required. Specifies the category of your event. NOTE: This value must be either `'ACTION_TRACKING'` or `'USER_ENGAGEMENT'`.       |
| action            | str                     | Required. Event name that will also serve as the KPI that you will have inside your reporting. [**Learn more**](doc:glossary#kpi) |

Methods are provided to set the following values:

| Builder Parameter | Type | Description                                                                                                                                                                                    |
| ----------------- | ---- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| label             | str  | Optional. Additional description of your event.                                                                                                                                                |
| value             | int  | Optional. Specifies the monetary value associated with an event (e.g. you earn 10 to 100 euros depending on the quality of lead generated). NOTE: this value must be non-negative integer > 0. |

### Caching visitor assignations

In some situations, you may need to cache visitor assignations. To do so, the Ruby SDK provides a useful module called **Flagship::VisitorCacheManager**.\
This module should be included and passed at configuration time, in order to get callbacks with the information to save or to load.

```ruby
class CustomVisitorCacheManager
    include Flagship::VisitorCacheManager

    def save(visitor_id, visitor_data)
        # Save visitor_data in your database.
    end

    def lookup(visitor_id)
        # Load and return visitor_data from your database, with the expected format.
    end
end


Flagship.instance.start(
    "_my_env_id",
    "_my_api_key_",
    Flagship::Config.new(event_handler=t, mode=Flagship::Config::Mode::BUCKETING, polling_interval:5, timeout:0.1, visitor_cache_manager:CustomVisitorCacheManager.new))
```

**`save(visitor_id, visitor_data)`**

Will be triggered after each call to synchronizationModification in order for you to save visitor assignations in your database.

| Parameter     | Type | Description                                            |
| ------------- | ---- | ------------------------------------------------------ |
| visitor\_id   | str  | Visitor identifier from which the data is coming from. |
| visitor\_data | dict | Dictionary containing the assignations to save.        |

**`lookup(visitor_id)`**

Will be triggered before each call to synchronizationModification in order for you to load visitor assignations from your database.

| Parameter   | Type | Description                                                    |
| ----------- | ---- | -------------------------------------------------------------- |
| visitor\_id | str  | Visitor identifier whose previous assignations must be loaded. |

#### Expected json format to return from lookup function.

```json
{
    "version": 1,
    "data": {
      "vId": "toto",
      "vaIds": [
        "bmsor064jaeg0gm41het",
        "bmsor064jaeg0gm4xxxx"
      ]
    }
}
```

| Key     | Type  | Description                                      |
| ------- | ----- | ------------------------------------------------ |
| version | int   | format version                                   |
| vId     | str   | Visitor identifier who belongs the assignations. |
| vaIds   | array | Array of variationId (assignations).             |

> 🚧 Caution
>
> Any other format will be ignored.

### Release notes

## 2.0.0

* Implement basic flow for Flagship instance and visitor
* Implement Decision API and Bucketing decision modes
* Implement hit tracking
* Implement visitor caching

### Appendix

#### Sources

SDK library sources are available [here](https://github.com/flagship-io/flagship-ruby-sdk).


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://docs.abtasty.com/server-side/sdks/ruby/ruby-v2x.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
