0

In rails I have data already in my database. I would like for certain things to be formatted certain ways no matter where it displays in my app. An example might be a social security number. In the database it might be stored as 123456789, but I want to display it as 123-45-6789 anywhere it shows up.

I know that I can format the output using string manipulation, but I wanted to know if there was a better way so that if I were to use,

<%= user.ssn %>

It would automatically get formatted correctly.

Update:

After much, MUCH research on my part, I came across the "lazy" way. You can override the default getter using the following in the User model.

def ssn
  read_attribute(:ssn).insert(5, '-').insert(3, '-')
end

My utter ignorance of proper terminology prevented me from finding this more easily. This sort of the is referred to as overriding a method and is discussed in the Rails documentation here.

All that being said I'll be writing a helper method which I originally thought of, but wanted to see if there was an easier way (i.e. less code writing). In the process I learned a lot about ActiveRecord, so my time not wasted. :-)

Other references:

Community
  • 1
  • 1
josephbales
  • 48
  • 1
  • 6

3 Answers3

1

The correct way would be something like what Richard said where you manipulate in some sort of ViewModel/PageObject/Decorator/Blahblah. The Rails way would be to use a helper method. The lazy way is to override your ssn getter in the User model to format super

Now you need to decide what kind of developer you are :]

Logan Serman
  • 29,447
  • 27
  • 102
  • 141
  • I ultimately chose the helper method way as my answer, but I found this answer to be the most helpful in my growth as a developer. Thanks :-) – josephbales Feb 01 '14 at 16:07
0

Use a view model. A bit like a presenter which is often done to add presentation logic, but which speaks the language of the view, a view model talks the language of the model but is just a simple decorator.

Instead of just passing an instance of user

@user = User.find(params[:id])

You would do something like

user = User.find(params[:id]
@user = UserView.new(user)

When I use a View Model it's usually a PORO decorate adding a few methods or overriding methods on User.

Here's a sample from a real application of mine, adapted to your question:

class ViewModelBase < SimpleDelegator

  def self.view_for(name)
    define_method(name) { __getobj__ }
  end

  def class
    __getobj__.class
  end
end


class UserView < ViewModelBase
  view_for :user

  def formatted_ssn
    formatting_rules(user.ssn)
  end

  def formatting_rules(ssn)
    # some rules for formatting an ssn
  end
end
Richard Jordan
  • 8,066
  • 3
  • 39
  • 45
  • Wow, just wow. I'm new to Rails and haven't heard of this approach yet. I will have to look into this some more. Thanks for the education. – josephbales Feb 01 '14 at 16:03
0

The standard approach is to create an Helper.

def format_ssn(value)
  # apply the transformation
end

<%= format_ssn(user.ssn) %>

If you want the value to always be outputted in that way, you can also consider to provide an alternative method in the model

class User
  def formatted_ssn
    # transform and return user.ssn
  end
end

You may see examples of people overriding the getter of ssn to properly format the value, but I strongly suggest you to avoid that approach. It may cause the formatted value to be stored in the database, overriding the original one.

Simone Carletti
  • 173,507
  • 49
  • 363
  • 364
  • Thanks for the response. This app is only going to be dealing with archived data, so I won't be writing to the database, but I'm going to take your advice anyway. This will be helpful to me in the future. – josephbales Feb 01 '14 at 16:00