创建名称助手,将名字和姓氏分开

我正在寻找一些关于如何获取属性并通过方法处理它以返回不同内容的帮助。 但我以前从未这样做过,我不确定从哪里开始。 我想改变一个名字:字符串属性从“乔治华盛顿”或“约翰昆西亚当斯”变成名字只有“乔治”和“约翰”。

我想也许帮助方法最好,比如

users_helper.rb

def first_name end 

然后调用@ user.name.first_name,这最初是如何工作的? 有人可以解释我下一步可以将@ user.name传递给方法吗? 我见过这样的事情,但不太明白括号……

 def first_name(name) puts name end 

有人可能会破坏rails / ruby​​这种类型的东西吗? 非常感谢!

括号(可选)括起参数列表。

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

这假设参数不是nil。

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

但这不是一个字符串方法,因为你的假设现在是:

 @user.full_name.first_name # Bzzt. 

代替:

 first_name @user.name 

这可以包含在模型类本身中:

 class User < ActiveRecord # Extra stuff elided def first_name self.full_name.blank? ? "" : self.full_name.split(" ")[0] end end 

额外的代码检查名称是否为blank?或空格( blank?来自Rails)。 如果是,则返回空字符串。 如果不是,则将其拆分为空格并返回结果数组中的第一项。

有些人有两个以上的名字,比如“John Clark Smith”。 您可以选择将它们视为:

(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 

上面的例子假设如果名称包含少于2个单词,那么它就是名字。

如果您只想拆分一次并提供这两个部件,这个衬里将起作用:

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

将最后一个单词作为姓氏,将其他所有内容作为名字。 因此,如果有一个前缀,“Dr.”,或者将包含在名字中的中间名。 显然,对于具有单独词语的姓氏,“Charles de Gaulle”它将无法工作,但处理更难(如果不是不可能的话)。

对于你要求的语法( @user.name.first_name ),Rails通过向基类型添加方法来做很多这种扩展,在你的例子中,你可以通过在String类上定义方法来实现。

 class String def given; self.split(' ').first end def surname; self.split(' ').last end end "Phileas Fog".surname # 'fog' 

另一种做这样的事情的方法是包装你要扩展的类型,这样你可以添加你想要的所有疯狂语法,而不会污染像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' 

正如Dave Newton的回答一样,这就是“姓氏”版本:

  def last_name self.full_name.blank? ? "" : self.full_name.split(" ")[-1] end 

让它变得简单

 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" 

谢谢

使用Ruby的Array#pop

根据我的需要,我需要使用其中包含1,2,3或更多“名称”的全名,如“AUSTIN”或“AUSTIN J GILLEY”。

助手方法

 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 

使用它

 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] 

您可以轻松地将first_namelast_name分配给:

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

您可以根据您的需要或想要对其进行修改。

 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 

输出:

 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"