---
title: "Better Rails Forms with Superform"
---

# Better Rails Forms with Superform

![Illustration of a web form, embodied as a superhero creature, punching the sun.](https://fly.io/ruby-dispatch/better-rails-forms-with-superform/assets/cover.webp)

[Annie Ruygt](https://annieruygtillustration.com/)

**Rails form helpers have been around for so long that they seem unquestionable, but did you know there’s a way to build forms in Rails that are easier to customize *and* permit their own strong parameters?**

[Superform](https://github.com/rubymonolith/superform) is a new form helper library built from scratch on top of [Phlex](https://www.phlex.fun) that makes building forms in Rails less tedious. Here’s what a Superform looks like:

```
# ./app/views/posts/form.rb
class Posts::Form < ApplicationForm
  def template(&)
    labeled field(:title).input
    labeled field(:body).textarea
  end

  # This would actually be in the ApplicationForm
  # superclass. It's added here for clarity.
  def labeled(component)
    div "p-4" do
      render component.field.label
      render component
    end
  end
end
```

It can then be rendered in Erb, HAML, or any other templating library. Like any view component: create an instance, pass it the `@post`, and you’ll see a form.

```
<h1>New post</h1>
<%= render Posts::Form.new @post %>
```

But the real superpower comes from creating an instance of the form in the controller so it can permit its own parameters.

```
class PostsController < ApplicationController
  include Superform::Rails::StrongParameters

  def create
    @form = Posts::Form.new(Post.new)
    @post = assign params.require(:post), to: @form

    if @post.save
      # Success path
    else
      # Error path
    end
  end
end
```

Never again will you wonder, “why is my form not updating?” in your Rails development environment only to realize you forgot to add a strong parameter to Rails. 🤦‍♂️

## How does Superform permit parameters?

Unlike Rails form helpers, Superform keeps tracks of the field names when the `field()` method is called in the view where you build the form. For example, in this form below the `:title` and `:body` attributes are passed into the `field` method, which adds them to an internal list of permitted parameters.

```
# ./app/views/posts/form.rb
class Posts::Form < ApplicationForm
  def template(&)
    labeled field(:title).input
    labeled field(:body).textarea
  end
end
```

Superform doesn’t actually use Rails strong parameters though—instead the `assign` method recursively goes through each `field` defined in the Superform and assigns the corresponding parameter to that field. If the field is not defined, its not assigned.

```
assign params.require(:post), to: @form
```

It’s not really magic, it’s just a form builder that’s both aware of its own structure *and* visual appearance. Contrast with Rails built-in form builders, which is only capable of describing visual its appearance without knowledge of the fields it’s permitting.

## Install Superform in your Rails app

If you’re read to get your hands dirty with Superform, add it to your Rails app.

```
$ bundle add superform
$ rails g superform:install
```

This installs Phlex and Superform in your Rails app. You’ll also see the `./app/views/application_form.rb` file in your Rails project that will look familiar to the forms above. Read the [Superform docs](https://github.com/rubymonolith/superform) to see how the form helpers work and have a look at the [Phlex website](https://www.phlex.fun/) to get a feel for the basics of how you’d build your own HTML components using Ruby.

## Customize the look and feel of forms

Since Superform is built on top of [Phlex](https://www.phlex.fun), inputs can be extended to emit the HTML markup your application needs from the `ApplicationForm` class. Here’s an example where we create a `MyInputComponent` class that includes inline error messages.

```
# ./app/views/forms/application_form.rb
class ApplicationForm < Superform::Rails::Form
  class MyInputComponent < ApplicationComponent
    def template(&)
      div class: "form-field" do
        input(**attributes)
        if field.errors?
          p(class: "form-field-error") { field.errors.to_sentence }
        end
      end
    end
  end

  class Field < Field
    def input(**attributes)
      MyInputComponent.new(self, attributes: attributes)
    end
  end
end
```

Additionally, methods can be added to the `ApplicationForm` class that makes common form tasks a bit easier.

```
class ApplicationForm
   def labeled(component)
    div class: "p-4" do
      render component.field.label
      render component
    end
  end

  def submit(text)
    button(type: :submit) { text }
  end
end
```

These methods can be called from form sub-classes and HTML will be emitted.

## Wrap up

[Superform](https://github.com/rubymonolith/superform) is a great way to create highly re-usable and customizable forms that permit their own parameters in Rails.

**Superform permits its own parameters** - Makes building forms much faster since you don’t have to worry about adding the parameter to the controller while building a form.

**Forms can be customized with Phlex components** - Superform is built from the ground-up with Phlex components. This makes it easier to mix regular HTML into the helper.

Superform is still a work in progress. It hasn’t reached 1.0 yet and features like `select > options` are still being developed, but already its being used for sophisticated form use cases, like [batch selection UI](https://github.com/rubymonolith/demo/blob/main/app/controllers/blogs/batch/posts_controller.rb) in a demo app.
