1

Rails humanizes attribute names automatically. I would like to make these humanized names title case. For example, MyModel.full_name is currently shown as 'Full name' but I would like the "n" capitalized: 'Full Name'.

I'm currently defining multi-word attributes in en.yml, which is not DRY at all. I would like to override .humanize. What's the best way to make .humanize work the way I want?

Bonus question:

Unfortunately, Rails' .titleize ignores English title rules. Words like 'a' and 'to' should not be capitalized, unless they're first or last word of the string. How can we fix this too?

MyModel.time_to_failure should be 'Time to Failure' but MyModel.send_to should be 'Send To'.

Jamie A.
  • 85
  • 1
  • 7
  • This may be useful: http://stackoverflow.com/questions/2842444/ruby-on-rails-converting-somewordhere-to-some-word-here – apod Jun 14 '16 at 16:38
  • How about do [`include HumanAttributeOverride`](https://gist.github.com/aruprakshit/113ee1e08d8f6efee2ddbbd2644e0463) in each model? `HumanAttributeOverride` is a concern module. – Arup Rakshit Jun 14 '16 at 16:52
  • If you have a small enough amount of words that won't be capitalized and you know the set, then do something like this: http://stackoverflow.com/questions/14251311/capitalizing-titles – unflores Jun 14 '16 at 18:20

1 Answers1

0

Thank you for your suggestions! @Arup Rakshit, your suggestion pointed me to ActiveModel::Translation#human_attribute_name, which turned out to be the way to do this in Rails 4.

Here's what I did:


Gemfile:

gem 'titleize'

config/initializers/human_attribute_name.rb:

# Overrides human_attribute_name so model attributes are title case.
# Combine with the titleize gem which overrides String#titleize with English-language rules.
module ActiveModel::Translation
  def human_attribute_name(attribute, options = {})
    options   = { count: 1 }.merge!(options)
    parts     = attribute.to_s.split(".")
    attribute = parts.pop
    namespace = parts.join("/") unless parts.empty?
    attributes_scope = "#{self.i18n_scope}.attributes"

    if namespace
      defaults = lookup_ancestors.map do |klass|
        :"#{attributes_scope}.#{klass.model_name.i18n_key}/#{namespace}.#{attribute}"
      end
      defaults << :"#{attributes_scope}.#{namespace}.#{attribute}"
    else
      defaults = lookup_ancestors.map do |klass|
        :"#{attributes_scope}.#{klass.model_name.i18n_key}.#{attribute}"
      end
    end

    defaults << :"attributes.#{attribute}"
    defaults << options.delete(:default) if options[:default]
    defaults << attribute.titleize

    options[:default] = defaults
    I18n.translate(defaults.shift, options)
  end
end

# If you're using Rails enums and the enum_help gem to make them translatable, use this code to default to titleize instead of humanize
module EnumHelp::Helper
  def self.translate_enum_label(klass, attr_name, enum_label)
    ::I18n.t("enums.#{klass.to_s.underscore.gsub('/', '.')}.#{attr_name}.#{enum_label}", default: enum_label.titleize)
  end
end

If you're not using enums and enum_help, delete the last bit.

A concern would have worked too, but in my project, there was no reason not to apply it to every model.

Beautiful!

Jamie A.
  • 85
  • 1
  • 7