Technology

Eleni Chappen

Using Active Storage with Active Model Serializers

Jul. 6, 2018

Attachment is the root of all suffering. If you’re a web developer, attachments are the root of all suffering.

Paperclip, a longtime go-to gem for managing file attachments, has been deprecated in favor of Active Storage, which is now officially part of Ruby on Rails as of version 5.2. So for a recent greenfield app, I took the dive into Active Storage.

Switching out dependable gems for new ones can be anxiety-inducing, but that’s web developer life. While Active Storage ended up being a breath of fresh air for many reasons, it came with a few of it’s own gotchas, particularly when dealing with querying data.

Active Storage and N+1 queries

Let’s say a user has one avatar. While Paperclip would add a few columns to your users table to store the avatar’s file data, file type, etc., Active Storage will create new tables that are solely responsible for keeping track of asset data and associating this data to your records.

These tables are called blobs and attachments. Blobs represent the actual metadata of the files, whereas Attachments are what join blobs (file data) to your application’s records (users). For every file you upload, a blob is created and associated to your record through an attachment.

These relationships are created when you attach a file through Active Storage using the has_one_attached shorthand:

class User < ApplicationRecord  
  has_one_attached :avatar

It’s important to understand these relationships between blobs and attachments when dealing with record queries that may have attachments.

For has_one_attached relationships, you can avoid N+1 queries by adding the with_attached_X method that Active Storage generates for you based on your attachment name:

User.with_attached_avatar.where(active: true)  

This is basically saying:

User.includes(avatar_attachment: :blob).where(active: true)  

I had to take special care of these relationships when using Active Model Serializers. Normally, when dealing with child records in a serializer, you can define a relationship using has_one or has_many:

class GameSerializer < ActiveModel::Serializer

  attributes :title

  has_many :users

If my User Serializer is using the avatar in any way, this would create an N+1 scenario:

class UserSerializer < ActiveModel::Serializer

  attributes :avatar_url

  def avatar_url
    ...object.avatar_url...

In order to avoid N+1 queries here, I had to ditch the built-in has_many and create a custom users method for the Game Serializer:

class GameSerializer < ActiveModel::Serializer

  attributes :title, :users

  def users
    User.with_attached_avatar.where(game_id: object.id)

Finding the right asset URL for serialization

When passing image urls through serializers, I had to search through some Active Storage Github issues and documentation to find the right url to use.

Creating images of smaller sizes is common for real-life use of your assets. Active Storage calls these variants. You’ll most likely use variants rather than the original asset in serializers.

If you want a url of the asset variant, include the Rails.application.routes.url_helpers module in your serializer, then use rails_representation_url in your url method:

class UserSerializer < ActiveModel::Serializer  
  include Rails.application.routes.url_helpers

  attributes :avatar_url

  def avatar_url
    variant = object.avatar.variant(resize: "100x100")
    return rails_representation_url(variant, only_path: true)
  end

If you want to use the original asset, use rails_blob_path instead:

return rails_blob_path(object.avatar, only_path: true)  

So there’s a little extra work when serialization is concerned, but overall I really enjoyed working with Active Storage and appreciate what a great thing this is for the Rails community.

Eleni Chappen

What People Are Reading

Operations

8/29/16

Watch us eat our own dog food

20spokes is trying a new diet, so to speak. If you’re unfamiliar with the phrase “eating your own dog food,” it’s a common expression in the software world referring to a developer’s practice of using their own products. It’s said to have originated from 1970s television advertisements for Alpo dog food, where the owner of the company would make a point of feeding Alpo to his own dogs. So in its broader interpretation, “practice what you preach” would be an appropriate alternative. Either way, if we can help others build great products, we want to show that we can build our own great products as well.

It’s something we’ve thought about for a while, and now we’re finally taking the steps to make it happen. Client work will still always be our primary focus, but we have the team, the experience, and the aspirations; why wouldn't we work on our own ideas too? Like our clients, though, we don't want to jump into these ventures haphazardly only to end up with a well built app that nobody else wants. So we're putting these ideas through the same process of discovery, validation, and planning that we would with anyone who came into our office. In a way, by becoming clients of our own process, we’re getting our first helping of dog food!

Over the last week or so, we’ve adopted the mindset of a founder with a vision, and taken one of our ideas through the first steps of conception. Working through this process as the “founder” has already given us some great new insight, and we're excited to share this journey with you. So stay tuned for the next several weeks as we document all the steps we take and lessons we learn along the way; we're going to find out just how good our dog food tastes.

Trying to get your own product idea to market? Contact us to learn more about our process and how we can help.

Technology

1/6/17

React Lessons for Newcomers

At 20spokes, developers spend a roughly equal amount of time between Ruby on Rails and React. While we enjoy working in both frameworks, they are quite different in approach, and going from a Rails way of thinking to a React way of thinking can be an adjustment.

One major way in which these frameworks are different is that Rails takes care of a lot of architectural issues that React leaves open for interpretation. Coming from a Rails background, I found the openness of React to be a bit anxiety-inducing at first, but I've come to really embrace it, because it's forced me to think more carefully than ever about how other developers would approach my code.

As a team, we've also considered what our best practices should be towards React, as we all want to make our code understandable and friendly to anyone who encounters it. To that end, below is a (growing) list of our approaches to making our React projects not only maintainable, but enjoyable to work with.

Be relentless with components

The basic building block of React is the component. To those new to React, they can best be thought of as modules.

As a developer, I start to get nervous when I see large components that perform various functions. The solution to keeping your files short and sweet is to take every opportunity to break your objects into re-useable components. Having larger components may not seem like a big deal when starting a project from scratch, but if you relentlessly component-ize you'll thank yourself as your project grows.

There are some code smells to recognize when you should create new components. If you see lots of groups of markup within a single div, those groups should probably be their own component.

If we have lots of renderXXX functions within in one component that render more markup, that's usually a code-smell that whatever is being returned from those functions should be their own component.

Make components as reusable as possible by passing dynamic data as props.

Privilege functional components over class-based ones

In many cases, it's overkill to Use React's Component class for every component you create. Not all components need access to the Lifecycle Methods or local state that Component provides. Start with stateless functional components and turn them into React Component instances as needed.

Take advantage of PropTypes

We started the practice of listing out PropTypes at the bottom of every component, so other developers can quickly reference what props are needed or optional. Oftentimes, we'd investigate what data we should expect in a component by looking up examples of that component elsewhere in the codebase. This easily can be avoided by using PropTypes, which provide a quick way to see what data is being passed, and of what type that data should be. Here's an example from our reusable Button component:

Button.propTypes = {  
  text: PropTypes.string.isRequired,
  onPress: PropTypes.func.isRequired,
  disabled: PropTypes.bool,
  icon: PropTypes.string,
}

We're pointing this out because, while Facebook already notes it as a best practice in their documentation, it's something that's easy to skip over or forget to do. But for something that's not hard to do at all, it provides a lot of value when developing and maintaining your app.

Use Lifecycle Methods with care

Despite being incredibly powerful, lifecycle methods (like ComponentDidUpdate) can cause a lot of headaches to those new to React. Be careful when updating state or props within these methods, as it may cause infinite looping.

For this reason, I prefer to place lifecycle methods at the very top of a component declaration, so I can see all of that logic together when debugging.

Check out part 2 of this series, Redux Lessons for Newcomers.

News

10/18/17

ChangeMaker Launches!

In a world where marches and protests are making weekly headlines, people are always looking for the next cause to get behind.

But what do you do when a cause or issue you’re passionate about needs more awareness and support? How do you find people to come together? How do you organize people, activities, events, and whatever else you might need to do? And if you do find people, how do you manage all the different moving parts?

And, well, what does that have to do with us at 20spokes?

Meet ChangeMaker -- a project we recently completed and launched.

Similar to sites like Kickstarter or Indiegogo, ChangeMaker allows organizations to add a project and find fellow activists to donate to or join the cause as a volunteer. The interface provides organizations the ability to detail an issue or problem, outline a solution, and how donors or volunteers can help. When people join the project as a volunteer, they can specify their particular skillset in fields such as marketing, design, legal, or data so project managers can delegate tasks to the right people.

With funding from donations, users can work on projects for their cause by using the free website. While most project management tools have some sort of fancy, pay-to-use features, ChangeMaker is completely free to use because it is donor funded and donor maintained.

We branded, designed, and coded the ChangeMaker platform in a Rails environment. We also integrated Stripe Connect, which enables organizations to receive those donations they need to power their projects.

Putting all this together sounds like it would take a good chunk of time, right? But we kicked off this project on August 8 and launched the website this week. A little more than two months. Not too shabby, eh? Just in time for the Newfounders Conference. ChangeMaker will have a big presence at the conference with donors ready to help out organizations that have ready-to-pitch projects for its demo night. Nothing is too small or too large for ChangeMaker to help its users and organizations tackle.

Give ChangeMaker a whirl at changemaker.newfounders.us.