Hash: extend for object attributes

Want to do some detective work regarding a thorny issue in your app? Ok lets use the handy inspect feature:


 :001 > User.last.inspect
 => "#<User id: 32, email: \"someemail@domain.com\", 
 encrypted_password: \"xxx\", job_function_id: nil, 
 reset_password_token: nil, reset_password_sent_at: nil, 
 remember_created_at: nil, sign_in_count: 0, 
 current_sign_in_at: nil, 
 last_sign_in_at: \"2016-12-23 16:00:35\", 
 current_sign_in_ip: nil, last_sign_in_ip: \"127.0.0.1\", 
 confirmation_token: nil, 
 confirmed_at: \"2016-12-23 16:00:34\", 
 confirmation_sent_at: nil, unconfirmed_email: nil, 
 first_name: \"Some\", last_name: \"Email\", 
 title: nil, company_id: 4373, 
 phone: \"0000000000\", 
 account_confirmation_link: nil, 
 password_reset_link: nil, 
 account_confirmation_link_date: nil, 
 password_reset_link_date: nil, 
 active: true, inactive_date: nil, 
 created_at: \"2016-12-23 16:00:34\", 
 updated_at: \"2016-12-23 16:42:18\", failed_attempts: 0, 
 unlock_token: nil, locked_at: nil>"

That is useful. I guess. What if we took out some of the #Object stuff by just looking at attributes


 :002 > User.last.attributes
 => {"id"=>32, "email"=>\"someemail@domain.com\", 
 "encrypted_password"=>"xxx", "job_function_id"=>nil, 
 "reset_password_token"=>nil, 
 "reset_password_sent_at"=>nil, 
 "remember_created_at"=>nil, 
 "sign_in_count"=>0, "current_sign_in_at"=>nil, 
 "last_sign_in_at"=>Fri, 23 Dec 2016 16:00:35 UTC +00:00, 
 "current_sign_in_ip"=>nil, "last_sign_in_ip"=>"127.0.0.1", 
 "confirmation_token"=>nil, 
 "confirmed_at"=>Fri, 23 Dec 2016 16:00:34 UTC +00:00, 
 "confirmation_sent_at"=>nil, 
 "unconfirmed_email"=>nil, "first_name"=>"Some", 
 "last_name"=>"Email", "title"=>nil, 
 "company_id"=>4373, "phone"=>"0000000000", 
 "account_confirmation_link"=>nil, 
 "password_reset_link"=>nil, 
 "account_confirmation_link_date"=>nil, 
 "password_reset_link_date"=>nil, 
 "active"=>true, "inactive_date"=>nil,
  "created_at"=>Fri, 23 Dec 2016 16:00:34 UTC +00:00, 
 "updated_at"=>Fri, 23 Dec 2016 16:42:18 UTC +00:00,
  "failed_attempts"=>0, "unlock_token"=>nil,
  "locked_at"=>nil}

Hmm. Not much better. How about I convert the attributes to JSON and then print them out:


 :003 > puts JSON.pretty_generate(JSON.parse(User.last.attributes.to_json))
 => {
      "id": 32,
      "email": "someemail@domain.com",
      "encrypted_password": "xxx",
      "job_function_id": null,
      "reset_password_token": null,
      "reset_password_sent_at": null,
      "remember_created_at": null,
      "sign_in_count": 0,
      "current_sign_in_at": null,
      "last_sign_in_at": "2016-12-23T16:00:35.333Z",
      "current_sign_in_ip": null,
      "last_sign_in_ip": "127.0.0.1",
      "confirmation_token": null,
      "confirmed_at": "2016-12-23T16:00:34.212Z",
      "confirmation_sent_at": null,
      "unconfirmed_email": null,
      "first_name": "Some",
      "last_name": "Email",
      "title": null,
      "company_id": 4373,
      "phone": "0000000000",
      "account_confirmation_link": null,
      "password_reset_link": null,
      "account_confirmation_link_date": null,
      "password_reset_link_date": null,
      "active": true,
      "inactive_date": null,
      "created_at": "2016-12-23T16:00:34.380Z",
      "updated_at": "2016-12-23T16:42:18.934Z",
      "failed_attempts": 0,
      "unlock_token": null,
      "locked_at": null
    }

Much improved. Gee a little sorting would be even better. Since we are dealing with a hash we need to sort into an array and then convert it back to a hash:


 :004 > puts JSON.pretty_generate(JSON.parse(User.last.attributes.sort.to_h.to_json))
 => {
   "account_confirmation_link": null,
   "account_confirmation_link_date": null,
   "active": true,
   "company_id": 4373,
   "confirmation_sent_at": null,
   "confirmation_token": null,
   "confirmed_at": "2016-12-23T16:00:34.212Z",
   "created_at": "2016-12-23T16:00:34.380Z",
   "current_sign_in_at": null,
   "current_sign_in_ip": null,
   "email": "someemail@domain.com",
   "encrypted_password": "xxx",
   "failed_attempts": 0,
   "first_name": "Some",
   "id": 16787,
   "inactive_date": null,
   "job_function_id": null,
   "last_name": "Email",
   "last_sign_in_at": "2016-12-23T16:00:35.333Z",
   "last_sign_in_ip": "127.0.0.1",
   "locked_at": null,
   "password_reset_link": null,
   "password_reset_link_date": null,
   "phone": "0000000000",
   "remember_created_at": null,
   "reset_password_sent_at": null,
   "reset_password_token": null,
   "sign_in_count": 0,
   "title": null,
   "unconfirmed_email": null,
   "unlock_token": null,
   "updated_at": "2016-12-23T16:42:18.934Z"
 }

Seems very useful for locating issues quickly. This would be great if we had this for a method for all hashes. Monkey Patch to the rescue. Lets call our initializer hash_extend.rb:


class Hash
  # pretty print
  def pretty
    puts JSON.pretty_generate(JSON.parse(self.sort.to_h.to_json))
    "=========== for display only ============="
  end
end

Restart your console and check out the pretty method:


 :001 > User.last.attributes.pretty
 => {
   "account_confirmation_link": null,
   "account_confirmation_link_date": null,
   "active": true,
   "company_id": 4373,
   "confirmation_sent_at": null,
   "confirmation_token": null,
   "confirmed_at": "2016-12-23T16:00:34.212Z",
   "created_at": "2016-12-23T16:00:34.380Z",
   "current_sign_in_at": null,
   "current_sign_in_ip": null,
   "email": "someemail@domain.com",
   "encrypted_password": "xxx",
   "failed_attempts": 0,
   "first_name": "Some",
   "id": 16787,
   "inactive_date": null,
   "job_function_id": null,
   "last_name": "Email",
   "last_sign_in_at": "2016-12-23T16:00:35.333Z",
   "last_sign_in_ip": "127.0.0.1",
   "locked_at": null,
   "password_reset_link": null,
   "password_reset_link_date": null,
   "phone": "0000000000",
   "remember_created_at": null,
   "reset_password_sent_at": null,
   "reset_password_token": null,
   "sign_in_count": 0,
   "title": null,
   "unconfirmed_email": null,
   "unlock_token": null,
   "updated_at": "2016-12-23T16:42:18.934Z"
 }
 => "=========== for display only ============="

Note we tack on for display only to the output just to identify the helper status of this method, since we are extending a core class.