• Quick Tip For Working With Mechanize

    The other day I came up with the great idea of publicly shaming myself if I didn’t make it to the gym in the past x days/weeks. It sounds rather twisted, but I’m in a good spot right now with my eating and fitness and I don’t want that to slip away. Being a developer, I thought this could be fun and relatively easy to do given easy access to a portal on my gym’s website that includes attendance records.

    Sounds like a good opportunity to work with Mechanize! I quickly found that my gym’s portal wasn’t as easy to parse using Mechanize as the examples used in the documentation. I found using the search method to look for the XPath of the elements I’m looking for would work well. With Chrome(and I assume other browsers), it’s rather simple to get the XPath of an element.

    I’ll use the Google homepage as an example since my gym’s page is a bit more cluttered.

    If you right click on an element of the page you want to find and inspect it. (I’m trying to find the Google Search button for some reason)

    Inspect Element Screenshot

    This will open up the DevTools window and highlight the element you’re looking for in the Elements tab. Now, if you right click the highlighted element, you’ll see an option to copy Copy XPath.

    Copy XPath Screenshot

    With the XPath copied you can use it in your search:

    agent.get('http://google.com').search("//*[@id='tsf']/div[2]/div[3]/center/input[1]")

    Hope this helps anyone in need of a quick way to find elements on a page using Mechanize. It’s worth noting that for pages that have a much simpler structure (like our example) it’ll be best to use the other methods of finding and interacting with elements on the page available in the documentation.

  • Creating Custom Validators in Rails

    Finally, a post about code! I found it odd that I started a blog intended to document my coding adventures and I have yet document anything related to code at all. So, the other night I was working on a personal rails project and I ran into a situation where the available rails validations were not quite what I needed.

    ###Validation Rules In my model had an attribute numbers which is an array of integers. In this array each number must be unique and must be one of the valid numbers allowed.

    ###Custom Methods One way to implement these validations is using custom methods. This is a great way to create a custom validation by using a private method in the model class that adds errors to the model when the attribute is invalid. To do this for our uniqueness validation rule we simply create a private validation method and call it using validate.

    class Game < ActiveRecord::Base
      serialize :numbers Array
    
      validate :numbers_are_unique
    
      private
      def numbers_are_unique
        # if there are duplicates numbers.uniq.count will be less than the actual count
        unless numbers.uniq.count == numbers.count
          errors.add(:numbers, 'is not a unique array')
        end
    end

    While this is great(and what I originally did), I wanted to explore creating a custom validator I could use across my app since I had another model that had a similar array of numbers that follows the same validations.

    ###Custom Validators The rails documentation has a great example of how to write a custom validator. This is what I followed to create two custom validators UniqueArrayValidator and InclusiveArrayValidator. Both these validators are not specific to my project and could be used with any array(even if the values are not integers). I placed them in app/validators, but others recommend putting them in lib/validators. If you put them in your lib folder you’ll have to make sure they’re loaded when rails starts.

    Here’s our new UniqueArrayValidator

    class UniqueArrayValidator < ActiveModel::EachValidator
      def validate_each(record, attribute, value)
        unless value.uniq.count == value.count
          record.errors[attribute] << (options[:message] || 'is not a unique array')
        end
      end
    end

    For our InclusiveArrayValidator we want to be able to pass in an array of valid values to check against. This is easily done by passing a value in the options hash.

    Here’s our InclusiveArrayValidator

    class InclusiveArrayValidator < ActiveModel::EachValidator
      def validate_each(record, attribute, value)
        valid_values = options[:valid_values]
        if value.any? { |n| !valid_values.include? n }
          record.errors[attribute] << (options[:message] || 'has invalid values')
        end
      end
    end

    ###Using Custom Validators Now we alter our model by removing the custom method and calling our new validators just as we would any built in rails validator. You can see we pass in the valid_values just as we would any other option needed for validations.

    class Game < ActiveRecord::Base
      VALID_NUMBERS = [1, 2, 3, 4, 5]
    
      serialize :numbers, Array
    
      validates :numbers, unique_array: true,
        inclusive_array: { valid_values: VALID_NUMBERS }
    end

    Now our numbers array is validated for uniqueness and that it only includes the values we deem valid for our use case. I hope this was helpful for anyone looking to implement a custom validator in their rails app. I’m open to suggestions on how to improve the validators, best practices, and even naming(I’m not sure inclusive is the correct way to describe that validation). Hell, maybe I missed out on a way to do this with the built in validators! Feel free to leave a comment.

  • Actually Being Productive

    One of my goals for this year has been to work on being more productive. It’s really easy to get swooped up in all the productivity books, apps, and podcasts all while not actually getting anything done!

    Here are the things I’ve done already to actually fulfil that goal:

    ###Wake up earlier I’ve found the first few hours of the day I can get a whole lot more done than the later hours of the day. Even if I don’t, I get all the potentially useless crap out of the way(twitter, hackernews, etc). An added bonus here is this has been making it much easier for me to get to the gym and exercise.

    ###Work in different places I’ve split my time lately working on the couch, my desk at home, and at the coworking space. I’m likely going to remove the couch from that equation, but it’s been nice to be somewhere else in my house getting things done. Plus, the couch, most likely, isn’t the best thing for my back and posture.

    ###Have a clear workspace My desk needs to be clean! At home this can be a challenge, but elsewhere I can’t store all my junk so it saves me the hassle of cleaning when I head to the coworking space!

    ###Have a clear mind This is a tough one for me, but I’ve found a solution! I simply started writing all my ideas, tasks, and everything down. Either in my calendar on my phone or Evernote. I’ve particularly grown fond of the reminder feature on Evernote for simple things I need to remember for today(like mailing out a bill that somehow doesn’t have online billpay…). This frees up my mind to focus on whatever task I need to be focusing on right now.

    These things are baby steps in the right direction. I’m hoping as this month closes out I can improve on my planning and scheduling. I really would like to be able to start a small side project I’ve had on the backburner, so having my day/week/month/year planned out will help me manage my time appropriately.