Serialization and check_box_tag in Rails 6

There are times when it is useful to simply store an array of arbitrary strings or numbers inside of one column, for example a list of tags for a simple blog application. Here we will see an example of controlling this array with simple check boxes in a Rails form.

Setup

NOTE: This guide assumes you already have Ruby and Rails 6.0 installed.

First create a new Rails project.

rails new serialized-checkboxes
cd serialized-checkboxes/

Create a home page and some scaffolding for a basic Post model.

rails generate controller home welcome
rails generate scaffold Post title:string body:text tags:text

Update the config/routes.rb to set the root route.

Rails.application.routes.draw do
  root 'home#welcome'
  resources :posts
end
/config/routes.rb

Create and migrate the database.

rails db:create
rails db:migrate

Serializing and Building the Form

Make the field serialized in app/models/post.rb.

class Post < ApplicationRecord
  serialize :tags
end
/app/models/post.rb

Build out the form in app/views/posts/_form.html.erb.

<% ['development', 'music', 'hiking'].each do |tag| -%>
  <%= label_tag "post[tags][#{tag}]", tag %>
  <%= check_box_tag "post[tags][#{tag}]", tag, @post.tags&.any?(tag) %>
<% end -%>
/app/views/posts/_form.html.erb

We create an array of tags and iterate through them using each. For each tag we create a label and a checkbox. We name both post[tags][#{tag}] so that our values will be passed in the correct format to the controller, as well as so that when the label is clicked it will activate the checkbox. Finally we use @post.tags&.any?(tag) to set the checkboxes as initially checked if those values are already in our serialized store.

Handling the Data

Inside app/controllers/posts_controller.rb we first add our fields to the parameter allowlist so they will get through from the form. Notice that the tags parameter is set as a hash at the end of the list.

def post_params
  params.require(:post).permit(
    :title, 
    :body, 
    tags: {}
  )
end
/app/controllers/posts_controller.rb

Create a new private method to format the data of the paramters how we want it, in this case we just want an array of the tag names stored in our serialized column.

def format_tags(parameters)
  parameters[:tags] = parameters[:tags].keys
  parameters
end
/app/controllers/posts_controller.rb

Now update the create and update methods to use our formatting method.

def create
  @post = Post.new(format_tags(post_params))

  respond_to do |format|
    if @post.save
       format.html { redirect_to @post, notice: 'Post was successfully created.' }
       format.json { render :show, status: :created, location: @post }
     else
       format.html { render :new }
       format.json { render json: @post.errors, status: :unprocessable_entity }
    end
  end
end
/app/controllers/posts_controller.rb
def update
  respond_to do |format|
    if @post.update(format_tags(post_params))
      format.html { redirect_to @post, notice: 'Post was successfully updated.' }
      format.json { render :show, status: :ok, location: @post }
    else
      format.html { render :edit }
      format.json { render json: @post.errors, status: :unprocessable_entity }
    end
  end
end
/app/controllers/posts_controller.rb

Finally, run the Rails server and view what we've done.

rails server
open https://localhost:3000

Conclusion

And that's it!

We can now navigate to http://localhost:3000/posts and create a new post using the checkboxes to store the tags we want for that post.

You can find the code for this tutorial on my GitHub.