RailsConf 2019

Learn to Make an API-Backed Model with Square’s Ruby SDK

Learn to Make an API-Backed Model with Square’s Ruby SDK

by Shannon Skipper

The video titled "Learn to Make an API-Backed Model with Square’s Ruby SDK" presented by Shannon Skipper at RailsConf 2019 focuses on leveraging the ActiveModel module in Ruby on Rails to create flexible models that interact with APIs rather than traditional databases. The speaker begins by discussing Active Resource, which is limited to Rails JSON APIs, and introduces ActiveModel as a more adaptable solution for various API interactions.

Key Points Discussed:
- Introduction to Active Resource: Active Resource allows for the modeling of remote Rails applications but is constrained by its reliance on a standard Rails JSON API. This inflexibility has limited its integration into Rails core.
- Active Model Overview: The speaker elaborates on how ActiveModel provides a model interface to APIs and not just databases. With the inclusion of ActiveModel::Model, features such as attribute assignment, validations, and error messages become available for non-database models.
- Attributes API: The latest Rails versions include an Attributes API that allows for type coercion and easier data handling for Ruby classes. Custom attribute types can be created for more complex structures.
- Implementing Callbacks: While ActiveModel doesn’t automatically implement callbacks, the speaker shows how to define lifecycle callbacks like save and update to mirror Active Record behavior.
- ActiveModel Dirty Tracking: This feature tracks changes in the model's attributes with minimal code, allowing the user to understand what has changed before committing updates to the API.
- Serialization: The speaker presents how models can be serialized to JSON easily, demonstrating how to convert models into hashes suitable for API interactions.
- Validations and I18n Support: Standard Rails validations are applicable, allowing for easily manageable data integrity within API calls. Internationalization support is also covered, enhancing user-friendliness.
- Usage of Pretty Print and Inspect: The speaker discusses implementing Pretty Print methods to enhance the visual representation of the model in rails console and IRB.
- Demonstration of Square API Integration: A real-world example is demonstrated using Square’s Customers API, showcasing how to fetch, update, and delete customer records seamlessly.
- Conclusion regarding Active Resource: The speaker concludes with guidance on when to use Active Resource versus ActiveModel, emphasizing the importance of CRUD operations and when a model is appropriately represented.

Takeaways: Shannon Skipper encourages developers to explore the capabilities of ActiveModel for building robust, API-backed models. He highlights that while Active Resource has its place, ActiveModel provides greater flexibility and power for non-standard data sources, ultimately enriching the Rails development experience.

00:00:20.840 Okay, hi! I'm going to start the talk. I'm Shannon Skipper, and I'm here talking about backing a model with an API instead of a database.
00:00:28.619 So, let's get started. First off, this is an idea that is as old as Rails.
00:00:35.449 Active Resource is something that ships under the Rails repository. It was never made part of Rails, but what it does is allow you to point a model at a remote Rails app.
00:00:42.000 It could be localhost, but it could also be over the web. It will then use the expected Rails JSON API to serialize and deserialize over the wire.
00:00:55.230 So here you can do customer.new, customers.save, or customers.update—everything you would expect, but it's an API.
00:01:01.620 The downside is that it has to be a Rails JSON API, and that was an edge case that was not flexible enough to be merged into Rails' main code base.
00:01:19.920 There are plenty of people who use this in production; it's really useful if you just need a direct connection to another Rails database.
00:01:32.940 So what if you want to go to the basics and create something more flexible than Active Resource? Because you have an API, but it's not a Rails API; it's not conventional Rails JSON.
00:01:39.989 If we look at the model, we can start with a simple customer class. This class really doesn't do anything on its own.
00:01:52.520 So what do the Active Model docs say about what we can add? We have attribute assignments, callbacks, conversions, dirty tracking, and more.
00:02:00.209 One single include will actually get you a pretty large swath of these features, and that's Active Model::Model.
00:02:07.770 When you include Active Model::Model, this code from that module will automatically include the attribute assignments, validations, conversions, naming, and translations.
00:02:14.280 So why does it do that? It is for Action Pack and Action View support, so when you're using your model in your view, it knows the things that Rails needs to know about the model for the automatic parts to work.
00:02:25.440 However, it doesn't include attributes, callbacks, dirty tracking, JSON serialization, serializers, or lint tests, so let's look at those individually.
00:02:45.060 First, let's take a look at attributes. If we want to add the attributes API to a bare Ruby class, what does that look like?
00:02:51.420 The attributes API is something that was added in recent Rails versions—specifically Rails 5.2. This is when Active Model attributes were added.
00:03:06.810 In Rails 5.2, you can take a bare Ruby class, say Customer, include Active Model Attributes, and go ahead and set your attributes.
00:03:12.870 These are typed attributes; for example, the name is a string, and the age is an integer. If we add the attributes API, we can set our age using a string like '42', and it will correctly return the integer '42' when queried.
00:03:25.170 Let me show you some more examples of the attributes API.
00:03:31.590 For example, I'm going to use Square's Customer API; it's one of many Square APIs available that support businesses. We have customer attributes like their ID and creation source, both strings, as well as attributes like preferences, creation time, and birthday.
00:03:50.630 These date times come out of the box, and this array of passions is actually defined by me. You can take the types Rails gives you out of the box, or you can create your own types.
00:04:04.320 You can also set a default, such as an empty string, for all these string field attributes. Let's briefly look at creating custom attributes. This is done in the config initializers, where I created a types.rb file—just a convention for where you put your types.
00:04:53.849 In this file, I have a hash type and all you need to define is the cast method for the desired operation. For example, the hash type takes keys and makes them symbols, while the array of hashes type iterates through an array and maps their keys to symbols.
00:05:31.530 Now, looking back at the customers file, you can see that I defined the type for the array of hashes, which allows for coercion when fetching the record. This is what makes the Attributes API really powerful—it gives you database-like type coercion while using an arbitrary data source.
00:05:44.280 Next, let’s talk about callbacks. This is one feature you have to implement yourself; it's not automatic, but it is part of the Active Model.
00:05:57.419 You define the model callbacks you want to have; I've defined update and save. By including this module, your model gets the ability to run these callbacks.
00:06:08.849 For example, when performing save and save bang, you can run the callbacks before and after these operations. This is a way to implement Active Record-style callbacks in your API-backed model.
00:06:25.380 Now, let’s touch on conversion. You can include ActiveModel::Conversion to provide partial paths. This is part of what makes Action Pack and Action View work seamlessly.
00:06:49.139 Next, we have ActiveModel::Dirty, which is another feature you don't get automatically. You will first need to include it, then define the will_change method. This allows Rails to track changes in the attributes.
00:07:40.170 ActiveModel::Dirty offers methods that tell Rails when attribute values have changed. You also need to implement the changes method to alert the model of persisted changes. This method sets an instance variable to track if the model’s state has been updated, which is particularly handy when working with data from an API.
00:08:42.780 Let me give you a code demo to illustrate this. If we fetch a customer from the API, we can modify some attributes, like setting the given name to 'Shannon' and the company name to 'Square'. With the Attributes API, the customer will track these changes correctly.
00:09:24.420 If we check the changes, we’ll see that the given name changed from 'Amy' to 'Shannon', and the company name changed from an empty string to 'Square'. And if we call save, it triggers an update against the API.
00:10:15.120 We can also restore the family name directly or restore all attributes. The dirty tracking helps us manage these updates just like Active Record, enabling seamless interaction with API-backed models.
00:11:18.840 Moving on, we have serializers provided by Active Model. This requires explicit inclusion, but it lets you convert your model to hashes easily, which is essential for JSON handling.
00:11:37.200 Similarly, validations work just as you would expect. By including Active Model::Model, you get access to built-in validations. For example, I have defined an 'email' validation, which will check the format before the API is called.
00:13:00.500 With Active Model, we get naming and translation support too, which is beneficial for internationalization. It enhances how we interact with the model and improves user experience.
00:14:15.690 Additionally, there's a lint test you can include in your tests. By including ActiveModel::Lint, you get 35 assertions and simple checks to validate your model's compliance with Rails expectations.
00:14:35.640 It's beneficial for ensuring that your model meets Rails’ standards, which helps maintain consistency across your codebase.
00:15:50.310 In the context of pretty printing and inspecting, these features provide a clear visual structure for debugging and interacting with your API-backed models.
00:16:00.200 Pretty print effectively highlights immutable fields versus regular attributes, giving an intuitive view while working in a console or REPL, thus improving the overall modeling experience.
00:16:45.900 So when interacting with the API, nothing happens until the model is saved, which helps delineate the operations between local model management and remote data updating.
00:17:50.400 Throughout the demo, I’ve utilized the Square Connect Ruby gem, which allows seamless integration into Rails applications. This demonstrates how we employ the Ruby SDK to manage and synchronize models effectively.
00:18:38.320 After creating models with the discussed attributes and modules, Rails interactions via controllers operate similarly to usual database-backed Active Record methods, enhancing developer efficiency.
00:19:30.900 Using pagination, editing records, and managing CRUD operations mirror a standard Rails workflow, showing the capability of the API-backed models to function seamlessly within Rails’ conventions.
00:20:39.150 As the talk wraps up, the approach to building a robust API-backed model can be refined. Integrating Active Model gives you plenty of functionalities to work effectively with remote data.
00:21:32.920 If you have any questions or comments, please tweet at us at Square Dev on Twitter. I'm Shannon Skipper, an engineer and evangelist at Square, and I'm thrilled to be working on our public Ruby infrastructure.