To further Max's
suggestion, I'd like to add that you can include address information inside a single model, if you want.
Having multiple models is cool, but if you're sure you only want certain attributes for your Client
, you can endeavour to save a hash of options to a column in there.
SQL
To answer your question directly, and to elaborate on Max's recommendation, there are several column types you can use, depending on the variant of SQL you're employing.
PostgreSQL (Heroku uses this) has the hstore
and json
column types.
Both of these provide you with a column which allows you to store a single serialized object, allowing you to populate this object with serialized data:

I've never used this functionality on PGSQL
before, so you'll be best reading this blog post on how to choose between HSTORE
and JSON
column types.
--
MYSQL, which most people use, also has the capacity to store JSON:
As of MySQL 5.7.8, MySQL supports a native JSON data type that enables
efficient access to data in JSON (JavaScript Object Notation)
documents. The JSON data type provides these advantages over storing
JSON-format strings in a string column:
This seems to work in the same way as its PGSQL brother.
If you do go for one of these (you could use the following setup):
#clients
#id | name | email | address (json) | created_at | updated_at
... it will give you the ability to insert JSON formatted objects into the address
column.
Now, as pointed out by Max
, this will prevent you from running validations
and other attribute-level logic on the address
column. It will prevent you from looking up this column through ActiveRecord, and will make it very difficult to use this data in any other capacity than just to store it.
Thus, if you were absolutely sure you wanted to store it in this way, you'd be able to use the following to do it:
#app/models/client.rb
class Client < ActiveRecord::Base
serialize :address
end
#app/controllers/clients_controller.rb
class ClientsController < ApplicationController
def new
@client = Client.new
end
def create
@client = Client.new client_params
@client.save
end
private
def client_params
params.require(:client).permit(:name, :email, address:{})
end
end
#app/views/clients/new.html.erb
<%= form_for @client do |f| %>
<%= f.text_field :name %>
<%= f.email_field :email %>
<%= f.fields_for :address, OpenStruct.new(f.object.address || {}) do |address| %>
<%= address.text_field :street %>
<%= address.text_field :other_data %>
<% end %>
<%= f.submit %>
<% end %>
fields_for
available here: How to edit a Rails serialized field in a form?
Models
The alternative, as pointed out by Max, is to use multiple models.
This, although looking good, is actually a very delicate process. Many people start inserting models for everything, and soon enough your application is full of models which don't do anything.
If you wanted to use models, you'd be best using the following:
#app/models/client.rb
class Client < ActiveRecord::Base
#columns id | name | email | etc | created_at | updated_at
has_one :address
before_create :build_address, unless: Proc.new { |client| client.address }
end
#app/models/address.rb
class Address < ActiveRecord::Base
#columns id | client_id | your | address | columns | here | created_at | updated_at
belongs_to :client
end
I would only recommend this if you wanted the address to play a major role in the application (IE if they are going to be shipping to it etc).
If you're using the address in any other non-important form, I'd leave it as the serialized hash.