DEV Community

Abraão Carvalho
Abraão Carvalho

Posted on

Performance and Optimization in Ruby on Rails

Performance and optimization in Ruby on Rails applications are crucial topics to ensure a fast and efficient experience for users. This involves several techniques, from caching to configuration and scalability adjustments.

Caching

Stores the HTML generated from pages in cache to serve quickly to subsequent users, avoiding the need to process the request again. Obviously this is super fast. Unfortunately, it cannot be applied to all situations (such as pages that need authentication) and since the web server is literally just serving a file from the file system, cache expiration is an issue that needs to be resolved.

To enable page caching, you need to use the "caches_page" method.

class ProductsController < ActionController

  caches_page :index

  def index
    @products = Products.all
  end
end
Enter fullscreen mode Exit fullscreen mode

Fragment Caching

Caches specific parts of pages, such as chunks of HTML, to reduce rendering time. For example, if you want to show all orders placed on your website in real time and you don't want to cache that part of the page, but you want to cache the part of the page that lists all available products, you could use this snippet of code:

<% Order.find_recent.each do |o| %>
  <%= o.buyer.name %> bought <%= o.product.name %>
<% end %>

<% cache do %>
  All available products:
  <% Product.all.each do |p| %>
    <%= link_to p.name, product_url(p) %>
  <% end %>
<% end %>
Enter fullscreen mode Exit fullscreen mode

The cache block in our example will be linked to the action that called it and will be written to the same location as the Action Cache, which means that if you want to cache multiple fragments per action, you must provide an "action_suffix" for the call. cache:

% cache(:action => 'recent', :action_suffix => 'all_products') do %>
  All available products:
Enter fullscreen mode Exit fullscreen mode

and you can expire using the "expire_fragment" method, like this:

expire_fragment(:controller => 'products', :action => 'recent', :action_suffix => 'all_products')
Enter fullscreen mode Exit fullscreen mode

If you don't want the cache block to be tied to the action that called it, you can also use global-key shards by calling the cache method with a key, like so:

<% cache('all_available_products') do %>
  All available products:
<% end %>
Enter fullscreen mode Exit fullscreen mode

This fragment is then available to all actions in the ProductsController using the key and can expire in the same way:

expire_fragment('all_available_products')
Enter fullscreen mode Exit fullscreen mode

Scalability

SQL query optimization, using indexes and sharding to distribute data across multiple databases is a Rails feature that caches the result set returned by each query so that if Rails encounters the same query again for that request, it will use the cached result set instead of running the query against the database again. For example:

class ProductsController < ActionController

  def index
    # Run a find query
    @products = Product.all

    ...

    # Run the same query again
    @products = Product.all
  end

end
Enter fullscreen mode Exit fullscreen mode

The second time the same query is executed against the database, it will not hit the database. The first time the query result is returned, it is stored in the query cache (in memory) and the second time it is extracted from memory.

Application Servers

Use of load balancers and horizontal scaling to handle increased traffic.

Example: Configuring application servers such as Puma or Unicorn for load balancing.

Distributed Cache

Using distributed caching to share data across multiple servers.

Example: Using Redis as a shared cache between application instances.

# Redis configuration for distributed cache in config/initializers/cache.rb
Rails.application.config.cache_store = :redis_store, {
  host: "localhost",
  port: 6379,
  db: 0,
  namespace: "app_cache"
}
Enter fullscreen mode Exit fullscreen mode

Configuration Settings

Environment Settings: Specific adjustments for different environments (development, production, testing) to optimize performance at each phase of the application lifecycle.

Example: Configuring different databases for test and production environments.

Server Tuning

Web server and database configuration adjustments for better performance.

Example: Configuring the maximum number of simultaneous connections on the web server.

Conclusion

In summary, optimizing the performance of Ruby on Rails applications involves a combination of intelligent caching, efficient scalability, and fine-tuning configuration. These practices ensure that the application can handle large volumes of traffic quickly and responsively, providing a better experience for users.

These are just a few examples of how performance and optimization techniques can be applied in real-world scenarios in Ruby on Rails applications.

Top comments (0)