Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Rails Model: Name -- First, Last

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?

like image 930
Andrew Avatar asked Oct 14 '10 05:10

Andrew


People also ask

What are rails models?

A Rails Model is a Ruby class that can add database records (think of whole rows in an Excel table), find particular data you're looking for, update that data, or remove data. These common operations are referred to by the acronym CRUD--Create, Remove, Update, Destroy.

What are active models in Rails?

Active Model is a library containing various modules used in developing classes that need some features present on Active Record.

What are Ruby models?

What are models? In simple terms, models are Ruby classes that can holds value of a single row in a database table. Since they all inherit ActiveRecord::Base through ApplicationRecord class, they are equipped with all the ActiveRecord methods which enables them to interact with the database.

What are model callbacks in rails?

Callbacks are methods that get called at certain moments of an object's life cycle. With callbacks it is possible to write code that will run whenever an Active Record object is created, saved, updated, deleted, validated, or loaded from the database.


2 Answers

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}"
end

Edit:

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}"
  end
end

This allows you to do:

user.profile.name.to_s  # John Doe
user.profile.name.first # John
user.profile.name.last  # Doe
like image 70
Mischa Avatar answered Sep 22 '22 20:09

Mischa


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
  end

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

  def to_s
    full_name
  end
end

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

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

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

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?

like image 41
François Beausoleil Avatar answered Sep 20 '22 20:09

François Beausoleil