0

This code is based on the idea of a Form Object http://blog.codeclimate.com/blog/2012/10/17/7-ways-to-decompose-fat-activerecord-models/ (see #3 if unfamiliar with the concept).

My actual code in question may be found here: https://gist.github.com/frankjmattia/82a9945f30bde29eba88

The code takes a hash of objects/attributes and creates a reverse lookup hash to keep track of their delegations to do this.

delegate :first_name, :email, to: :user, prefix: true 

But I am manually creating the delegations from a hash like this:

DELEGATIONS = { user: [ :first_name, :email ] } 

At runtime when I want to look up the translated attribute names for the objects, all I have to go on are the delegated/prefixed (have to use a prefix to avoid naming collisions) attribute names like :user_first_name which aren't in sync with the rails i18n way of doing it:

en: activerecord: attributes: user: email: 'Email Address' 

The code I have take the above delegations hash and turns it into a lookup table so when I override human_attribute_name I can get back the original attribute name and its class. Then I send #human_attribute_name to the original class with the original attribute name as its argument.

The code I've come up with works but it is ugly to say the least. I've never really used #inject so this was a crash course for me and am quite unsure if this code effective way of solving my problem. Could someone recommend a simpler solution that does not require a reverse lookup table or does that seem like the right way to go?

Thanks, - FJM

1 Answer 1

0

I think I would keep the actual class constants intact so you're not jumping through ActiveSupport's library so much and also immediately build the delegations table instead of also having the REVERSE_DELEGATIONS constant. Finally, refactor the humanize_attribute_name into two lines for clarity's sake.

class RegistrationForm DELEGATIONS = { User => [ :first_name, :first_name=, :last_name, :last_name=, :email, :email=, :password, :password=, :password_confirmation, :password_confirmation= ], Organization => [ :name, :name= ] }.map{|klass, attrs| attrs.map{|attr| {:"#{klass.to_s.downcase}_#{attr}" => [klass, attr]}}}.flatten.reduce({}, :merge) def self.human_attribute_name(method) klass, attribute = DELEGATIONS[method] klass ? klass.send(:human_attribute_name, attribute) : method end end 

You could also further refine the reverse_mapping to create both :user_first_name, and :user_first_name= from just :first_name and do away with the always paired declarations.

1
  • Well it certainly looks a lot cleaner. I hadn't though about using actual class constants, I'll have to play around with this when I get home and see how it works. If it does the trick I'll accept the answer. Thankya. Commented Jan 2, 2014 at 21:24

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.