Home > Software design >  Properly capitalizing each word within a model's row in Active Record
Properly capitalizing each word within a model's row in Active Record

Time:08-21

I'm working in Ruby and ActiveRecord albeit not full Rails; it's really just Sinatra serving the backend. I have an Artist model, that only contains an id and a name. What I'm aiming to do is capitalize (by use of titleize) each name, such that if any word follows a space it's to be capitalized.

I can make this happen with names in an array (self.cleanup works) but I can't do it within an object. (self.fixer doesn't) I have pictures below of each function's Pry output.

class Artist < ActiveRecord::Base
  has_many :songs
  has_many :genres, through: :songs
  has_many :reviews, through: :songs

  accepts_nested_attributes_for :genres, :songs

  # stores an array of all the artists' names
  def self.names
    all.pluck(:name)
  end

  # cleans up the names of each Artist, capitalizes all
  def self.cleanup
    unique_array = self.names.uniq
    unique_array.map { |string| string.titleize }
  end

  # capitalizes each name within the Artist model
  def self.fixer
    self.all.each do |artist|
      artist.name.titleize
    end
  end
end

Here is my Artist.fixer function, which doesn't work

Here is my Artist.cleanup function, which does

CodePudding user response:

When calling

self.all.each { |artist| artist.name.titleize }

Ruby will iterate over all artists and call titleize on their name. But titleize will not change the string on which it is called, it only returns a titleized version of the string. Because you do not store the returned titleized string it is not persisted after the each call.

Instead, change your method to this and reassign the titleized version to the artist's name:

def self.fixer
  self.all.each do |artist|
    artist.name = artist.name.titleize
  end
end

Please note that this only changes the artist's name in the array returned from the fixer method. it does not update and permanently fix the name in the database. Therefore you might want to consider fixing names before saving the name into the database. Then you would not need to fix it each time again when reading a record from the database.

CodePudding user response:

Managed to figure it out, as a two-stepper for anyone confused reading this in posterity.

(1) Defining the function, hereby called title_fixer. (2) Putting a before_save :title_fixer header within my class.

class Artist < ActiveRecord::Base
  has_many :songs
  has_many :genres, through: :songs
  has_many :reviews, through: :songs

  accepts_nested_attributes_for :genres, :songs
  before_save :title_fixer

  ## corrects the title capitilzation
  ## always launched before an artist saves

  def title_fixer
    ## add a case to capitalize after [&, -, /]
    self.name = self.name.split(/ |\_/).map(&:capitalize).join(" ")
  end
end

Only thing left to do is work with the regex to include cases for "&", "-", and "/" -- for example to capitalize "Hip-hop -> Hip-Hop" and "R&b/soul -> R&B/Soul". Otherwise, it seems to work well.

  • Related