Take the 2-minute tour ×

I'm fairly new to rails, working on a Rails 3 app with a Profile model for users.

In the profile Model I'd like to have a "name" entry, and I'd like to be able to access logical variations of it using simple syntax like:

user.profile.name = "John Doe"
user.profile.name.first = "John"
user.profile.name.last = "Doe"

Is this possible, or do I need to stick with "first_name" and "last_name" as my fields in this model?

share|improve this question
add comment

4 Answers

up vote 9 down vote accepted

It's possible, but I wouldn't recommend it.

I would just stick with first_name and last_name if I were you and add a method fullname:

def fullname
  "#{first_name} #{last_name}"


If you really do want user.profile.name, you could create a Name model like this:

class Name < ActiveRecord::Base
  belongs_to :profile

  def to_s
    "#{first} #{last}"

This allows you to do:

user.profile.name.to_s  # John Doe
user.profile.name.first # John
user.profile.name.last  # Doe
share|improve this answer
Ok, advice noted. For the sake of me learning Ruby would you mind showing how the "possible but not recommended" approach would work? –  Andrew Oct 14 '10 at 5:17
Sure, just a sec... –  Mischa Oct 14 '10 at 5:21
Agreed. We just spent almost six months spliting a single name into multiple fields because some idiot "designed" the database using a single field for that name. Worse off our customer service reps would also put company names into that field because there was not business name field! I wish I knew who designed that database so I could smack 'em on the nose with a newspaper and say, "No! Bad programmer! Bad!" –  Mike Bethany Oct 14 '10 at 5:23
Cool, thanks for all the feedback and ideas all. I'll stick with first_name and last_name and use the fullname method to give me the options I need :) –  Andrew Oct 14 '10 at 5:53
add comment

The other answers are all correct, in so far as they ignore the #composed_of aggregator:

class Name
  attr_reader :first, :last

  def initialize(first_name, last_name)
    @first, @last = first_name, last_name

  def full_name
    [@first, @last].reject(&:blank?).join(" ")

  def to_s

class Profile < ActiveRecord::Base
  composed_of :name, :mapping => %w(first_name last_name)

# Rails console prompt
> profile = Profile.new(:name => Name.new("Francois", "Beausoleil"))
> profile.save!

> profile = Profile.find_by_first_name("Francois")
> profile.name.first

As noted on the #composed_of page, you must assign a new instance of the aggregator: you cannot just replace values within the aggregator. The aggregator class acts as a Value, just like a simple string or number.

I also sent a response yesterday with a very similar answer: How best to associate an Address to multiple models in rails?

share|improve this answer
add comment

FYI (assume you have a field fullname. ie your profile.name = "John Doe")

class Profile
  def name
    @splited_name ||= fullname.split # @splited_name would cache the result so that no need to split the fullname every time

Now, you could do something like this:

user.profile.fullname   # "John Doe"
user.profile.name.first # "John"
user.profile.name.last  # "Doe"

Note the following case:

user.profile.fullname = "John Ronald Doe"
user.profile.name.first  # "John"
user.profile.name.second # "Ronald"
user.profile.name.last   # "Doe"

I agree with captaintokyo. You won't miss out the middle names. Also this method assume no Chinese, Japanese names are input. It's because those names contain no spaces in between first name and last name normally.

share|improve this answer
add comment

As Capt. Tokyo said that's a horrible idea but here's how you would do it:

rails g model User full_name:hash

Then you would store data in it like so:

user = User.new
user.full_name = {:first => "Forrest", :last => "Gump"}

Now your problems begin.

To search the field requires both names and you can't do a partial search like searching for all people with the same last name. Worst of all you can store anything in the field! So imagine another programmer mistypes one of the field names so for a week you have {:fist => "Name", :last => "Last"} being inserted into the database! Noooooooooooooooooo!

If you used proper field names you could do this:

user = User.new(:first_name => "First", :last_name => "Last")

Easy to read and no need for hashes. Now that you know how to do it the wrong way, do it the right way. :)

share|improve this answer
I'll go ahead and forget how to do this. I had no idea this was even possible. –  Jason Noble Oct 14 '10 at 11:28
add comment

Your Answer


