creating name helper, to split first and last names apart
Asked Answered
N

8

7

I'm looking for some help on how to take an attribute and process it through a method to return something different. But I've never done this before and I' not sure where to start. I thought trying to change a name:string attribute from "George Washington" or "John Quincy Adams" into first names only "George" and "John".

I thought maybe a helper method would be best, such as

users_helper.rb

def first_name

end

and then call @user.name.first_name, would this be initially how it would work? Can someone explain where I'd go next to be able to pass @user.name into the method? I've seen things like this but don't quite understand it the parenthesis...

def first_name(name)
  puts name
end

Could someone breakdown how rails/ruby does this type of thing? Thanks a lot!

Nye answered 5/11, 2011 at 22:52 Comment(1)
Ever seen Ellie Mae Clampett on the TV show "The Beverly Hillbillies"?Clovis
M
7

The parentheses (which are optional) enclose the parameter list.

def first_name(full_name)
  full_name.split(" ")[0]
end

This assumes the parameter is not nil.

> puts first_name "Jimmy McKickems"
Jimmy
> puts first_name "Jeezy"
Jeezy

But this is not a string method, as your assumption is now:

@user.full_name.first_name # Bzzt.

Instead:

first_name @user.name

This could be wrapped up in the model class itself:

class User < ActiveRecord
  # Extra stuff elided

  def first_name
    self.full_name.blank? ? "" : self.full_name.split(" ")[0]
  end
end

The extra code checks to see if the name is nil or whitespace (blank? comes from Rails). If it is, it returns an empty string. If it isn't, it splits it on spaces and returns the first item in the resulting array.

Muttra answered 5/11, 2011 at 23:6 Comment(2)
Be aware that this can bite you if people enter "Dr. Jimmy Jeezy" as their name. You'll end up with first_name as "Dr."Bacchus
@DaveBryand Of course. It also makes several other assumptions, all in line with the OP's question.Muttra
T
17

Some people have more than two names, such as "John Clark Smith". You can choose to treat them as:

(1) first_name: "John", last_name: "Smith"

  def first_name
    if name.split.count > 1
      name.split.first
    else
      name
    end
  end

  def last_name
    if name.split.count > 1
      name.split.last
    end
  end

(2) first_name: "John Clark", last_name: "Smith"

  def first_name
    if name.split.count > 1
      name.split[0..-2].join(' ')
    else
      name
    end
  end

  def last_name
    if name.split.count > 1
      name.split.last
    end
  end

(3) first_name: "John", last_name: "Clark Smith"

  def first_name
    name.split.first
  end

  def last_name
    if name.split.count > 1
      name.split[1..-1].join(' ')
    end
  end

The above examples assume that if the name contains less than 2 words then it is a first name.

Toname answered 3/6, 2014 at 5:10 Comment(0)
M
7

The parentheses (which are optional) enclose the parameter list.

def first_name(full_name)
  full_name.split(" ")[0]
end

This assumes the parameter is not nil.

> puts first_name "Jimmy McKickems"
Jimmy
> puts first_name "Jeezy"
Jeezy

But this is not a string method, as your assumption is now:

@user.full_name.first_name # Bzzt.

Instead:

first_name @user.name

This could be wrapped up in the model class itself:

class User < ActiveRecord
  # Extra stuff elided

  def first_name
    self.full_name.blank? ? "" : self.full_name.split(" ")[0]
  end
end

The extra code checks to see if the name is nil or whitespace (blank? comes from Rails). If it is, it returns an empty string. If it isn't, it splits it on spaces and returns the first item in the resulting array.

Muttra answered 5/11, 2011 at 23:6 Comment(2)
Be aware that this can bite you if people enter "Dr. Jimmy Jeezy" as their name. You'll end up with first_name as "Dr."Bacchus
@DaveBryand Of course. It also makes several other assumptions, all in line with the OP's question.Muttra
A
6

In case you are looking to split only once and provide both parts this one liner will work:

last_name, first_name = *name.reverse.split(/\s+/, 2).collect(&:reverse)

Makes the last word the last name and everything else the first name. So if there is a prefix, "Dr.", or a middle name that will be included with the first name. Obviously for last names that have separate words, "Charles de Gaulle" it won't work but handling that is much harder (if not impossible).

Akanke answered 15/1, 2015 at 15:48 Comment(0)
P
3

Use Ruby's Array#pop

For my needs I needed to take full names that had 1, 2, 3 or more "names" in them, like "AUSTIN" or "AUSTIN J GILLEY".

The Helper Method

def split_full_name_into_first_name_and_last_name( full_name )
  name_array = full_name.split(' ')   # ["AUSTIN", "J", "GILLEY"]
  
  if name_array.count > 1                   
    last_name  = name_array.pop       # "GILLEY"
    first_name = name_array.join(' ') # "AUSTIN J"

  else                                      
    first_name = name_array.first           
    last_name  = nil
  end

  return [ first_name, last_name ]    # ["AUSTIN J", "GILLEY"]
end

Using It

split_full_name_into_first_name_and_last_name( "AUSTIN J GILLEY" )
# => ["AUSTIN J", "GILLEY"]

split_full_name_into_first_name_and_last_name( "AUSTIN" )
# => ["AUSTIN", nil]

And you can easily assign the first_name and last_name with:

first_name, last_name = split_full_name_into_first_name_and_last_name( "AUSTIN J GILLEY" )

first_name
# => "AUSTIN J"

last_name
# => "GILLEY"

You can modify from there based on what you need or want to do with it.

Peculiar answered 20/12, 2017 at 3:2 Comment(0)
D
1

For the syntax you're asking for (@user.name.first_name) Rails does a lot of this sort of extension by adding methods to base types, in your example you could do this through defining methods on the String class.

class String
  def given; self.split(' ').first end
  def surname; self.split(' ').last end
end

"Phileas Fog".surname # 'fog'

Another way to do something like this is to wrap the type you whish to extend, that way you can add all the crazy syntax you wish without polluting more base types like string.

class ProperName < String
  def given; self.split(' ').first end
  def surname; self.split(' ').last end
end

class User
  def name
    ProperName.new(self.read_attribute(:name))
  end
end

u = User.new(:name => 'Phileas Fog')
u.name # 'Phileas Fog'
u.name.given # 'Phileas'
u.name.surname # 'Fog'
Discourse answered 5/11, 2011 at 23:9 Comment(1)
Won't work if name is "John", because it produces "John John" Also it drops everything between first and last word.Milone
M
1

Just as complement of great Dave Newton's answer, here is what would be the "last name" version:

  def last_name
    self.full_name.blank? ? "" : self.full_name.split(" ")[-1]
  end
Midge answered 7/12, 2013 at 2:29 Comment(0)
F
1

making it simple

class User < ActiveRecord::Base

  def first_name
    self.name.split(" ")[0..-2].join(" ")
  end

  def last_name
    self.name.split(" ").last
  end
end

User.create name: "John M. Smith"
User.first.first_name
# => "John M."
User.first.last_name
# => "Smith"

Thanks

Forward answered 22/12, 2015 at 5:16 Comment(0)
D
0
def test_one(name)
  puts "#{name.inspect} => #{yield(name).inspect}"
end

def tests(&block)
  test_one nil, &block
  test_one "", &block
  test_one "First", &block
  test_one "First Last", &block
  test_one "First Middle Last", &block
  test_one "First Middle Middle2 Last", &block
end

puts "First name tests"
tests do |name|
  name.blank? ? "" : name.split(" ").tap{|a| a.pop if a.length > 1 }.join(" ")
end

puts "Last name tests"
tests do |name|
  name.blank? ? "" : (name.split(" ").tap{|a| a.shift }.last || "")
end

Output:

First name tests
nil => ""
"" => ""
"First" => "First"
"First Last" => "First"
"First Middle Last" => "First Middle"
"First Middle Middle2 Last" => "First Middle Middle2"

Last name tests

nil => ""
"" => ""
"First" => ""
"First Last" => "Last"
"First Middle Last" => "Last"
"First Middle Middle2 Last" => "Last"
Dillondillow answered 29/6, 2016 at 15:40 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.