120

I'm trying to get Rails to capitalize the first character of a string, and leave all the others the way they are. I'm running into a problem where "i'm from New York" gets turned into "I'm from new york."

What method would I use to select the first character?

Thanks

EDIT: I tried to implement what macek suggested, but I'm getting a "undefined method `capitalize'" error. The code works fine without the capitalize line. Thanks for the help!

def fixlistname! self.title = self.title.lstrip + (title.ends_with?("...") ? "" : "...") self.title[0] = self.title[0].capitalize errors.add_to_base("Title must start with \"You know you...\"") unless self.title.starts_with? 'You know you' end 

EDIT 2: Got it working. Thanks for the help!

EDIT 3: Wait, no I didn't... Here's what I have in my list model.

def fixlistname! self.title = self.title.lstrip + (title.ends_with?("...") ? "" : "...") self.title.slice(0,1).capitalize + self.title.slice(1..-1) errors.add_to_base("Title must start with \"You know you...\"") unless self.title.starts_with? 'You know you' end 

EDIT 4: Tried macek's edit, and still getting an undefined method `capitalize'" error. What could I be doing wrong?

def fixlistname! self.title = title.lstrip self.title += '...' unless title.ends_with?('...') self.title[0] = title[0].capitalize errors.add_to_base('Title must start with "You know you..."') unless title.starts_with?("You know you") end 

EDIT 5: This is weird. I'm able to get rid of the undefined method error by using the line below. The problem is that it seems to replace the first letter with a number. For example, instead of capitalizing the y in You, it turns the y into a 121

self.title[0] = title[0].to_s.capitalize 
5
  • Based on EDIT 3, you need to start line 2 with self.title = . Also, on all 3 lines, you only need self.title on the left of an = (equal sign). In other places you can just use title. See the edit on my answer for an example. Commented Apr 15, 2010 at 16:49
  • 2
    The problem in Edit4 is that you've got just a character - no longer a string - therefore it won't recognise the string-function "capitalize". Commented Apr 21, 2010 at 14:05
  • Problem with Edit 5 is that title[0] is a fixnum, so calling title[0].to_s will just give you the character number (i.e 121 as a string: "121"). You can do self.title[0] = title.first.capitalize if you want! Commented Mar 29, 2012 at 22:29
  • 1
    I added a #upcase_first_case and made a pull request: github.com/rails/rails/pull/15319. Feel free to add your feedback there. Commented May 25, 2014 at 19:28
  • Props to upcase_first < answer there for anyone using Rails 5+. Credit @user1519240. Would be a good accepted answer if @DanielOConnor ever revisits this :) Commented Oct 16, 2020 at 15:01

18 Answers 18

133

This should do it:

title = "test test" title[0] = title[0].capitalize puts title # "Test test" 
Sign up to request clarification or add additional context in comments.

5 Comments

@JonGarvin title[0].capitalize doesn't work (at least with Ruby 1.8.7), as title[0] returns a Fixnum, and capitalize expects a string.. so I think title.first.capitalize is the way to go.
shame you can't title.first.capitalize!
capitalize converts all letters after the first letter to lowercase, so it dosn't work for the string presented in the question ("i'm from New York").
Sorry I know this is old but thought I'd respond. We are only calling capitalize on the first character here, not the whole string, so it does work.
More shorter, title[0] = title[0].upcase
96

Titleize will capitalise every word. This line feels hefty, but will guarantee that the only letter changed is the first one.

new_string = string.slice(0,1).capitalize + string.slice(1..-1) 

Update:

irb(main):001:0> string = "i'm from New York..." => "i'm from New York..." irb(main):002:0> new_string = string.slice(0,1).capitalize + string.slice(1..-1) => "I'm from New York..." 

7 Comments

Wait, still not working. False alarm :/ I think I'm just implementing it wrong.
Daniel - it's generally good form to "accept" an answer that solved your problem. You can do this by clicking the "tick" to the left of the answer. :)
I misunderstood the question, otherwise I wanted to give you a 1 up. I was looking for .titleize instead of .capitalize. Thank you anyway Taryn!
OOC - Why does that stop you from giving an upvote? Did I correctly answer the original poster's question? If you think so - then upvote. It doesn't have to be dependent on anything else... :)
So, here it goes: s[0].capitalize + s[1..-1] if s.present?
|
79

As of Rails 5.0.0.beta4 you can use the new String#upcase_firstmethod or ActiveSupport::Inflector#upcase_first to do it. Check this blog post for more info.

So

"i'm from New York...".upcase_first 

Will output:

"I'm from New York..." 

2 Comments

Thats great news! I was thinking what we can do right now and maybe a polyfill for Rails 4 would be nice.
Note that upcase_first and doesn't handle accents/special chars, even with mb_chars
64

You can use humanize. If you don't need underscores or other capitals in your text lines.

Input:

"i'm from New_York...".humanize 

Output:

"I'm from new york..." 

5 Comments

The OP specifically wanted to avoid 'new york'
Hmm indeed, little bit too fast with my answer.
@Bartuzz Even though this isn't what OP wanted, this is exactly what I was looking for. Thanks!
new york however would be ungrammatical as its a proper noun and should use capitals.
Be warned, humanize is the Rails, exactly ActiveSupport method. Plain ruby can not do that.
59
str = "this is a Test" str.sub(/^./, &:upcase) # => "This is a Test" 

4 Comments

Concise and elegant. I believe this should be the top answer.
I agree. I think this should be the accepted answer.
One quirk is that since ^ means beginning of line, "\nfoo" becomes "\nFoo". That's probably fine for most use cases. Since it's a sub and not a gsub, it will still only upcase one letter, even with multiline strings.
Can get the limitation above by using str.sub(/\S/, &:upcase), which will find the first non-whitespace character and upcase it.
14

An object oriented solution:

class String def capitalize_first_char self.sub(/^(.)/) { $1.capitalize } end end 

Then you can just do this:

"i'm from New York".capitalize_first_char 

2 Comments

At least somebody wrote elegant solution with extending of String class.
@Dmitriy why is monkey patching the string class elegant?
8
str.sub(/./, &:capitalize) 

Comments

6

Edit 2

I can't seem to replicate your trouble. Go ahead and run this native Ruby script. It generates the exact output your looking for, and Rails supports all of these methods. What sort of inputs are you having trouble with?

#!/usr/bin/ruby def fixlistname(title) title = title.lstrip title += '...' unless title =~ /\.{3}$/ title[0] = title[0].capitalize raise 'Title must start with "You know you..."' unless title =~ /^You know you/ title end DATA.each do |title| puts fixlistname(title) end __END__ you know you something WITH dots ... you know you something WITHOUT the dots you know you something with LEADING whitespace... you know you something with whitespace BUT NO DOTS this generates error because it doesn't start with you know you 

output

You know you something WITH dots ... You know you something WITHOUT the dots... You know you something with LEADING whitespace... You know you something with whitespace BUT NO DOTS... RuntimeError: Title must start with "You know you..." 

Edit

Based on your edit, you can try something like this.

def fixlistname! self.title = title.lstrip self.title += '...' unless title.ends_with?('...') self.title[0] = title[0].capitalize errors.add_to_base('Title must start with "You know you..."') unless title.starts_with?("You know you") end 

Original

This will do the trick

s = "i'm from New York" s[0] = s[0].capitalize #=> I'm from New York 

When trying to use String#capitalize on the whole string, you were seeing I'm from new york because the method:

Returns a copy of str with the first character converted to uppercase and the remainder to lowercase.

"hello".capitalize #=> "Hello" "HELLO".capitalize #=> "Hello" "123ABC".capitalize #=> "123abc" 

4 Comments

+1 cause I didn't think that would work till I tried it on my pc :)
Hi, thanks for the help. What am I doing wrong though? I've edited the original question to include my code.
I used Taryn's suggestion and got it working. Thanks for the help though!
Hi, stackoverflow says you made an edit, but I don't see anything different?
6
my_string = "hello, World" my_string.sub(/\S/, &:upcase) # => "Hello, World" 

1 Comment

Does not fail if my_string is empty! Nice. This is what I need.
3

No-one's mentioned gsub, which lets you do this concisely.

string.gsub(/^([a-z])/) { $1.capitalize } 

Example:

 > 'caps lock must go'.gsub(/^(.)/) { $1.capitalize } => "Caps lock must go" 

Comments

3

Most of these answers edit the string in place, when you are just formatting for view output you may not want to be changing the underlying string so you can use tap after a dup to get an edited copy

'test'.dup.tap { |string| string[0] = string[0].upcase } 

Comments

3

If and only if OP would want to do monkey patching on String object, then this can be used

class String # Only capitalize first letter of a string def capitalize_first self.sub(/\S/, &:upcase) end end 

Now use it:

"i live in New York".capitalize_first #=> I live in New York 

Comments

2

An even shorter version could be:

s = "i'm from New York..." s[0] = s.capitalize[0] 

Comments

1

Note that if you need to deal with multi-byte characters, i.e. if you have to internationalize your site, the s[0] = ... solution won't be adequate. This Stack Overflow question suggests using the unicode-util gem

Ruby 1.9: how can I properly upcase & downcase multibyte strings?

EDIT

Actually an easier way to at least avoid strange string encodings is to just use String#mb_chars:

s = s.mb_chars s[0] = s.first.upcase s.to_s 

Comments

1

Rails starting from version 5.2.3 has upcase_first method.

For example, "my Test string".upcase_first will return My Test string.

Comments

0

Perhaps the easiest way.

s = "test string" s[0] = s[0].upcase # => "Test string" 

Comments

0
"i'm from New York".camelize => "I'm from New York" 

2 Comments

While this may work, from a semantic point-of-view, I'm not sure that camelize tells me that it will capitalize the first character. In C# world, for example, we call capitalizing the first word "Pascal case," and lower case first word "camel case."
This is not the same: i'm from New York C_1".camelize => "I'm from New York C1", the "_" has disapeared
-3
string = "i'm from New York" string.split(/\s+/).each{ |word,i| word.capitalize! unless i > 0 }.join(' ') # => I'm from New York 

2 Comments

Seems so. I'm new to ruby, and the other answers didn't actually do what the OP asked, so I made it work :D Correct me if I'm wrong, but AFAIK modifying a string by changing string[i] doesn't work in a lot of languages?
this is a Ruby-specific question. It doesn't matter if string[i] doesn't work in other languages. Please help keep StackOverflow clutter-free of these kind of hacked-up answers. We can't say RTFM, but even a quick glance at the String docs would've helped avoid an answer like this...