Topics Covered in This Ruby on Rails Tutorial:
Converting Product Data to JSON APIs, Generating XML Feeds, and Leveraging Active Admin for Advanced CSV Export Functionality
Exercise Overview
In this comprehensive exercise, you'll master the essential skill of data syndication—a critical capability for modern web applications that need to share information with partners, third-party services, or mobile applications. We'll explore multiple data export formats and implement professional-grade API endpoints.
If you completed the previous exercises, you can skip the following sidebar. We strongly recommend completing exercises 8A–11B before proceeding, as this tutorial builds upon the foundation established in those lessons. If you haven't finished them, follow the setup instructions below.
Data Syndication BenefitsBy providing structured data feeds, you eliminate manual data entry for partners and ensure they always have up-to-date information from your site.
If You Did Not Complete the Previous Exercises (8A–11B)
- Close any open files in your editor to ensure a clean workspace.
- Open the Finder and navigate to Class Files > yourname-Rails Class
- Launch Terminal.
- Type
cdfollowed by a single space (do NOT press Return yet). - Drag the yourname-Rails Class folder from the Finder to the Terminal window and press ENTER.
- Run
rm -rf nuttyto remove any existing copy of the nutty site. - Run
git clone https://bitbucket.org/Noble Desktop/nutty.gitto download the That Nutty Guy repository. - Type
cd nuttyto enter the project directory. - Type
git checkout 11Bto bring the site up to the end of the previous exercise. - Run
bundleto install required Ruby gems. - Run
yarn install --check-filesto install JavaScript dependencies.
Converting Product Info into a JSON Feed
Imagine you've negotiated a partnership with a prominent comedy blog that wants to feature your products on their website. Rather than forcing them to manually input product information—which would be time-consuming and prone to outdated data—you'll create a dynamic JSON API endpoint. This approach ensures partners always have access to current product information and pricing.
JSON APIs have become the de facto standard for data exchange between modern web applications. By implementing this functionality, you're following industry best practices used by companies like Shopify, Amazon, and countless SaaS platforms.
For this exercise, we'll continue working with the nutty folder located in Desktop > Class Files > yourname-Rails Class > nutty
We recommend opening the entire nutty folder in your code editor (most modern editors like VS Code, Sublime Text, or Atom support this) to enable quick file navigation and project-wide search capabilities.
Ensure you have a Terminal window with two tabs open from the previous exercise—the first should be running the Rails server. If not, complete the server restart procedure below.
“Any controller action can respond to different formats of a request and render its output in different ways
This is the power of Rails respond_to helper method for multi-format APIsData Security ConsiderationAlways use the 'only' parameter to limit which fields are exposed in your API to prevent accidentally sharing sensitive data like cost or MAP pricing.
Restarting the Rails Server
- In Terminal, navigate to the nutty folder:
- Type
cdand a space. - Drag the nutty folder from Desktop > Class Files > yourname-Rails Class onto the Terminal window to auto-complete the path.
- Press Return to change directory.
In Terminal, start the Rails development server:
rails s- Open a new tab (Cmd–T) while keeping the server running in the original tab.
- In the new tab, navigate to the nutty folder using the same process as step 1.
In your code editor, open nutty > app > controllers > products_controller.rb
We'll modify the existing index action to support JSON responses. This leverages Rails' built-in content negotiation system, allowing the same controller action to serve different formats based on the request.
Starting around line 7, add the following code to enable multi-format responses:
def index
@get_nutty = true
@products = Product.all
respond_to do |format|
format.html
format.json { render json: @products }
end
end
NOTE: The respond_to helper is a powerful Rails feature that enables content negotiation. This pattern allows your API to serve both human-readable HTML and machine-readable JSON from the same endpoint—a hallmark of RESTful design.
Save the file and keep it open for further modifications.
In your browser, navigate to the standard products page: localhost:3000/products
This displays the familiar HTML interface your users see.
Now access the JSON API endpoint: localhost:3000/products.json
You should see a JSON feed containing all product information from the previous step. This endpoint can now be consumed by any application capable of making HTTP requests—mobile apps, partner websites, or internal analytics tools.
Let's test the API programmatically. In Terminal, start the Rails console:
rails cExecute an HTTP request against your own API:
r = HTTParty.get('http://localhost:3000/products.json')
This demonstrates how external services would interact with your API.
Explore the returned data with these console commands:
r.count
r.first['title']
You should receive the total number of products (8) and the title of the first product (Tinfoil Hat).
While this works perfectly for Ruby on Rails applications, there's a significant security consideration: we're exposing all product data. In a production environment, you might have sensitive information like wholesale costs, profit margins, or internal notes that shouldn't be public.
Let's implement proper data filtering. Return to products_controller.rb in your code editor.
Modify the JSON response to include only specific fields:
format.json { render json: @products, only: [:title, :sku, :price] }
This approach follows the principle of least privilege—exposing only the data necessary for partners to function.
Save the file and test your changes.
Refresh the API endpoint in your browser: localhost:3000/products.json
The response now contains only the title, SKU, and price for each product—much cleaner and more secure for public consumption.
Adding a Model Method
Let's enhance our API by providing partners with direct promotional links. This approach reduces friction for partners and ensures consistent link formatting across all integrations.
In your code editor, open nutty > app > models > product.rb
We'll add a custom method that generates partner-friendly URLs using the product's slug.
Around line 15, add a method to generate promotional links:
friendly_id :title, use: [:slugged, :finders] def partner_link "https://www.thatnuttyguy.com/products/#{slug}" end endThis method creates SEO-friendly URLs that partners can use directly in their content.
Save and close the model file.
Return to nutty > app > controllers > products_controller.rb
Include the new method in your JSON response (note the comma):
format.json { render json: @products, only: [:title, :sku, :price], methods: [:partner_link] }The
methodsparameter allows you to include custom model methods in JSON serialization—a powerful way to add computed values to your API responses.Save the file and test the enhanced API.
Refresh your browser at: localhost:3000/products.json
Perfect! Each product now includes a complete URL that partners can use for direct linking, improving user experience and tracking capabilities.
Adding Partner-Friendly Data
Create Model Method
Add partner_link method to Product model using the friendly URL slug
Include in API Response
Use methods parameter in render json to include computed values alongside database fields
Creating an XML File
Real-world integrations often require flexibility in data formats. Suppose your partner's content management system can't parse JSON but requires XML instead. Rails' multi-format support makes this transition seamless.
Return to your products_controller.rb file in the code editor.
Add XML support by duplicating and modifying the JSON format line:
format.json { render json: @products, only: [:title, :sku, :price], methods: [:partner_link] } format.xml { render xml: @products.as_json(only: [:title, :sku, :price], methods: [:partner_link]) }Note the
.as_json()method call—this ensures the XML output includes the same filtered fields and custom methods as our JSON endpoint.Save the file and test the new format.
Navigate to the XML endpoint: localhost:3000/products.xml
You now have a fully functional XML feed! This demonstrates Rails' philosophy of convention over configuration—adding new formats requires minimal code changes. While we're converting to JSON first then to XML (a pragmatic shortcut), Rails provides more sophisticated XML generation for complex use cases.
JSON vs XML Implementation
| Feature | JSON | XML |
|---|---|---|
| Syntax | render json: @products | render xml: @products.as_json |
| Processing | Direct rendering | Convert to JSON first |
| File Extension | .json | .xml |
CSV Exports
Data export requirements often extend beyond API endpoints. Let's address a common business need: providing the accounting department with CSV exports for order analysis. Active Admin's built-in export functionality offers a professional solution with minimal configuration.
First, we need to register orders as an Active Admin resource. In Terminal, exit the Rails console and generate the resource:
exit rails g active_admin:resource orderThis command creates the necessary configuration files for managing orders through the admin interface.
To test the integration, we need sample order data. Navigate to: localhost:3000
Add several products to your cart if it's currently empty.
Proceed to the Cart page and complete the checkout process by clicking Checkout.
Access the admin panel: localhost:3000/admin
Sign in if prompted. If you don't have admin credentials or are working from a prepared folder, use the login creation process below.
Active Admin Power FeatureActive Admin automatically provides CSV, XML, and JSON download links for any registered resource without additional configuration.
Export Customization Options
Default Exports
Active Admin automatically generates basic exports with all model attributes included in the output.
Custom CSV Blocks
Override default behavior with custom column definitions, computed values, and formatted date displays.
Creating Admin Access
Use the default credentials to access the system:
Email: admin@example.com Password: password In the gray navigation bar, click Admin Users.
Click Edit next to admin@example.com.
Update the credentials with your information:
Email: your email address (Use an account accessible during class) Password: student1 Click Update Admin user to save changes.
- Re-authenticate using your new credentials.
If you encounter authentication issues, try this alternative approach:
Creating User Credentials via Terminal
- Open a new Terminal tab using Cmd–T
- Access the Rails console:
rails c Create admin credentials programmatically:
AdminUser.create :email => 'admin@example.com', :password => 'password', :password_confirmation => 'password'- Return to http://localhost:3000/admin in your browser to log in.
Complete steps 2–6 from the previous sidebar to customize your account.
Once logged in, click the Orders link in the navigation.
Notice the download links below the order listing—Active Admin automatically provides CSV, XML, and JSON export functionality.
Click the CSV download link to export the data.
Open the downloaded file in Excel or your preferred spreadsheet application if it doesn't open automatically.
The default export provides basic information, but accounting departments typically need more comprehensive data. We could modify the index page display, but that would affect the web interface. Instead, let's create a custom CSV export configuration.
In your code editor, open nutty > app > admin > order.rb
Remove any commented-out placeholder code to start with a clean configuration.
Add a comprehensive CSV export configuration:
ActiveAdmin.register Order do
csv do
column :id
column :email
column :total
column("Products") { |o| o.products.collect(&:title).join(", ") }
column("Order Date") { |o| o.created_at.strftime("%-m/%-d/%Y %-I:%M%p") }
end
end
This configuration creates a business-friendly export with order ID, customer email, total amount, product list, and formatted order date. The custom date formatting converts Rails' default military time to a more readable format that accounting teams expect.
Save the configuration file.
Test the enhanced export by reloading: localhost:3000/admin/orders.csv (or return to the Orders page and click the CSV download link)
Your custom export now provides comprehensive order information ready for accounting analysis, financial reporting, and business intelligence applications.
Keep Terminal, your code editor, and browser open—we'll continue building upon this foundation in the next exercise.