Serialized Attributes

Episode #4 by Teacher's Avatar David Kimura

Summary

Store multiple attributes and values using a text column. Not for everyday use, but has situations where it can save on the number of columns and/or models needed to accomplish a task.
rails model 12:04

Resources

Summary

Create the users scaffold with name and properties

# bash
    rails g scaffold users name properties:text

Add serialized attributes on `properties` and the singleton methods for our serialized attributes.

# user.rb
    serialize :properties, Hash
    after_initialize do
      %w(twitter_handle github_username).each do |property|
        define_singleton_method property do
          properties[property]
        end
      end
    end

Add the properties array to the allowed parameters

# users_controller.rb
    def user_params
      #params.require(:user).permit(:name, properties: [:twitter_handle, :github_username])
      params.require(:user).permit(*user_attributes)
    end

    def user_attributes
      property_fields = [:twitter_handle, :github_username]
      [].tap do |attributes|
        attributes << :name
        attributes << { properties: property_fields }
      end
    end

    def user_attributes
      property_fields = []
      params.require(:user).each do |key, p|
        property_fields << p.keys if key == 'properties'
      end

      property_fields = [:twitter_handle, :github_username]
      [].tap do |attributes|
        attributes << :name
        attributes << { properties: property_fields }
      end
    end


Create the form fields for the serialized attributes

# _form.html.erb
    <%= f.simple_fields_for :properties do |p| %>
      <%= p.input :twitter_handle, input_html: { value: @user.properties[:twitter_handle] } %>
      <%= p.input :github_username, input_html: { value: @user.properties[:github_username] } %>
    <% end %>

Display the parameters

# index.html.erb
    <table class='table table-bordered table-condensed'>
      <thead>
        <tr>
          <th>Name</th>
          <th>Twitter</th>
          <th>Github</th>
          <th colspan="3"></th>
        </tr>
      </thead>

      <tbody>
        <% @users.each do |user| %>
          <tr>
            <td><%= user.name %></td>
            <td>
              <%# user.properties[:twitter_handle] %>
              <%= user.twitter_handle %>
            </td>
            <td>
              <%# user.properties[:github_username] %>
              <%= user.github_username %>
            </td>
            <td><%= link_to 'Show', user %></td>
            <td><%= link_to 'Edit', edit_user_path(user) %></td>
            <td><%= link_to 'Destroy', user, method: :delete, data: { confirm: 'Are you sure?' } %></td>
          </tr>
        <% end %>
      </tbody>
    </table>