Create an account

Very important

  • To access the important data of the forums, you must be active in each forum and especially in the leaks and database leaks section, send data and after sending the data and activity, data and important content will be opened and visible for you.
  • You will only see chat messages from people who are at or below your level.
  • More than 500,000 database leaks and millions of account leaks are waiting for you, so access and view with more activity.
  • Many important data are inactive and inaccessible for you, so open them with activity. (This will be done automatically)


Thread Rating:
  • 528 Vote(s) - 3.44 Average
  • 1
  • 2
  • 3
  • 4
  • 5
Why does Rails titlecase add a space to a name?

#1
Why does the `titlecase` mess up the name? I have:

John Mark McMillan

and it turns it into:

>> "john mark McMillan".titlecase
=> "John Mark Mc Millan"

Why is there a space added to the last name?

Basically I have this in my model:

before_save :capitalize_name

def capitalize_name
self.artist = self.artist.titlecase
end

I am trying to make sure that all the names are titlecase in the DB, but in situtations with a camelcase name it fails. Any ideas how to fix this?
Reply

#2
We have just added this which supports a few different cases that we face.

```ruby
class String
# Default titlecase converts McKay to Mc Kay, which is not great
# May even need to remove titlecase completely in the future to leave
# strings unchanged
def self.custom_title_case(string = "")
return "" if !string.is_a?(String) || string.empty?

split = string.split(" ").collect do |word|
word = word.titlecase

# If we titlecase and it turns in to 2 words, then we need to merge back
word = word.match?(/\w/) ? word.split(" ").join("") : word

word
end

return split.join(" ")
end
end

```

And the rspec test

```
# spec/lib/modules/string_spec.rb
require 'rails_helper'
require 'modules/string'

describe "String" do
describe "self.custom_title_case" do
it "returns empty string if incorrect params" do
result_one = String.custom_title_case({ test: 'object' })
result_two = String.custom_title_case([1, 2])
result_three = String.custom_title_case()

expect(result_one).to eq("")
expect(result_two).to eq("")
expect(result_three).to eq("")
end

it "returns string in title case" do
result = String.custom_title_case("smiths hill")
expect(result).to eq("Smiths Hill")
end

it "caters for 'Mc' i.e. 'john mark McMillan' edge cases" do
result_one = String.custom_title_case("burger king McDonalds")
result_two = String.custom_title_case("john mark McMillan")
result_three = String.custom_title_case("McKay bay")

expect(result_one).to eq("Burger King McDonalds")
expect(result_two).to eq("John Mark McMillan")
expect(result_three).to eq("McKay Bay")
end

it "correctly cases uppercase words" do
result = String.custom_title_case("NORTH NARRABEEN")
expect(result).to eq("North Narrabeen")
end
end
end
```
Reply

#3
The "Why" question has already been [answered][1]...but as evidenced by the selected answer and upvotes, I think what most of us are ACTUALLY wanting is a silver bullet to deal with the hell that is name-formatting...While multiple capitals trigger that behavior, I've found that hyphenated names do the same.

These cases and many more have already been handled in the gem, **[NameCase][2]**.

In version 2.0 it only converts a string if the string is all uppercase or all lowercase, based on a defined ruleset as a best guess. I like this, because I'm sure the ruleset can never be 100% correct. Example, ***Ian McDonald (from Scotland) has a different capitalization from Ian Mcdonald (from Ireland)***...however those names will be handled correctly at the time of input if the user is particular and if not, the name can be corrected if needed and retain its formatting.

***My Solution:***

# If desired, add string method once NameCase gem is added
class String

def namecase
NameCase(self)
end

end

**Tests: (name.namecase)**

test_names = ["john mark McMillan", "JOHN CAPSLOCK JOE", "test name", "test name-name", "test McName-name", "John w McHENRY", "ian mcdonald", "Ian McDonald", "Ian Mcdonald"]

test_names.each { |name| puts '# "' + name + '" => "' + name.namecase + '"' }
# "john mark McMillan" => "John Mark McMillan"
# "JOHN CAPSLOCK JOE" => "John Capslock Joe"
# "test name" => "Test Name"
# "test name-name" => "Test Name-Name"
# "test McName-name" => "Test McName-Name"
# "John w McHENRY" => "John w McHENRY" -FAIL
# "ian mcdonald" => "Ian McDonald"
# "Ian McDonald" => "Ian McDonald"
# "Ian Mcdonald" => "Ian Mcdonald"


If you feel you need to handle all of the corner cases on this page and don't care about losing names that may have been formatted at the start, *eg. Ian Mcdonald (from Ireland)*...you could use `upcase` first:

**Tests: (name.upcase.namecase)**

test_names.each { |name| puts '# "' + name + '" => "' + name.upcase.namecase + '"' }
# "john mark McMillan" => "John Mark McMillan"
# "JOHN CAPSLOCK JOE" => "John Capslock Joe"
# "test name" => "Test Name"
# "test name-name" => "Test Name-Name"
# "test McName-name" => "Test McName-Name"
# "John w McHENRY" => "John W McHenry"
# "ian mcdonald" => "Ian McDonald"
# "Ian McDonald" => "Ian McDonald"
# "Ian Mcdonald" => "Ian McDonald"


The only silver bullet is to go old school...ALL CAPS. But who wants that eyesore in their modern web app?


[1]:

[To see links please register here]

[2]:

[To see links please register here]

Reply

#4
If you want to handle the case where someone has entered `JOHN CAPSLOCK JOE` as well as the others, I combined this one:

class String
def proper_titlecase
if self.titleize.split.length == self.split.length
self.titleize
else
self.split(" ").collect{|word| word[0] = word[0].upcase; word}.join(" ")
end
end
end

Depends if you want that kinda logic on a String method ;)
Reply

#5
You may also encounter names with two capital letters, such as McLaren, McDonald etc.

Have not spent time trying to improve it, but you could always do

**Code**

# Rails.root/config/initializers/string.rb
class String
def titleize_name
self.split(" ")
.collect{|word| word[0] = word[0].upcase; word}
.join(" ").gsub(/\b('?[a-z])/) { $1.capitalize }
end
end

**Examples**

[2] pry(main)> "test name".titleize_name
=> "Test Name"
[3] pry(main)> "test name-name".titleize_name
=> "Test Name-Name"
[4] pry(main)> "test McName-name".titleize_name
=> "Test McName-Name"
Reply

#6
You can always do it yourself if Rails isn't good enough:

class String
    def another_titlecase
        self.split(" ").collect{|word| word[0] = word[0].upcase; word}.join(" ")
    end
end

"john mark McMillan".another_titlecase
=> "John Mark McMillan"


This method is a small fraction of a second faster than the regex solution:

My solution:

ruby-1.9.2-p136 :034 > Benchmark.ms do
ruby-1.9.2-p136 :035 > "john mark McMillan".split(" ").collect{|word|word[0] = word[0].upcase; word}.join(" ")
ruby-1.9.2-p136 :036?> end
=> 0.019311904907226562


Regex solution:

ruby-1.9.2-p136 :042 > Benchmark.ms do
ruby-1.9.2-p136 :043 > "john mark McMillan".gsub(/\b\w/) { |w| w.upcase }
ruby-1.9.2-p136 :044?> end
=> 0.04482269287109375
Reply

#7
**Edited** (inspired by The Tin Man's suggestion)

A hack will be:

class String
def titlecase
gsub(/(?:_|\b)(.)/){$1.upcase}
end
end

p "john mark McMillan".titlecase
# => "John Mark McMillan"

Note that the string `'john mark McMillan'` is inconsistent in capitalization, and is somewhat unexpected as a human input, or if it is not from a human input, you probably should not have the strings stored in that way. A string like `'john mark mc_millan'` is more consistent, and would more likely appear as a human input if you define such convention. My answer will handle these cases as well:

p "john mark mc_millan".titlecase
# => "John Mark McMillan"

Reply

#8
You're trying to use a generic method for converting Rail's internal strings into more human readable names. It's not designed to handle "Mc" and "Mac" and "Van Der" and any number of other compound spellings.

You can use it as a starting point, then special case the results looking for the places it breaks and do some fix-ups, or you can write your own method that includes special-casing those edge cases. I've had to do that several times in different apps over the years.
Reply

#9
The [documentation][1] for titlecase says ([emphasis added]):

> Capitalizes all the words ***and replaces
> some characters in the string*** to
> create a nicer looking title. titleize
> is meant for creating pretty output.
> It is not used in the Rails internals.

I'm only guessing here, but perhaps it regards PascalCase as a problem - maybe it thinks it's the name of a `ActiveRecordModelClass`.

[1]:

[To see links please register here]

Reply

#10
Hmm, that's odd.. but you could write a quick custom regex to avoid using that method.

class String
def custom_titlecase
self.gsub(/\b\w/) { |w| w.upcase }
end
end

"John Mark McMillan".custom_titlecase # => "John Mark McMillan"

[Source](

[To see links please register here]

)
Reply



Forum Jump:


Users browsing this thread:
1 Guest(s)

©0Day  2016 - 2023 | All Rights Reserved.  Made with    for the community. Connected through