Cory O'Daniel – These are just words Software development, thoughts, and randomness

17Nov/112

Rails 3 Easy Search forms using SimpleForm and ActiveModel

For the sites I'm currently working on I have search pages all over the place for different resources, especially on the backend. In the past I would forego using form builders and just do some HTML to make a form GET the data. I hate HTML.

So I did some poking around to see what I could do to DRY up my time on creating these search forms. My first thought was to create a Search class and use active model, but it sucked because I everytime I had to create a new form I had to come into the search class and add a bunch of attr_accessors for all of the search fields. That sucks.

So I decided to mix it up with OpenStruct and ActiveModel

require 'ostruct'
class Search < OpenStruct
  include ActiveModel::Validations
  include ActiveModel::Conversion
  extend  ActiveModel::Naming
 
  def initialize(*args)
    super
  end
 
  def persisted? ; false ; end;
end

Now I use this one model for searching of all of my resources.

I create the form super easily with SimpleForm:

= simple_form_for(@search, url: my_cool_path(), html:{method: :get}) do |f|
  = f.input :text
  = f.select :category,  Product::CATEGORIES
  = f.input :minimum_price
  = f.input :maximum_price
  = f.submit :search

In your controller you are going to get a params[:search] hash with :text, :category, :minimum_price, :maximum_price.

Want to persist that search across page reloads?

class ApplicationController < ActionController::Base
  before_filter :persist_search
  protected
  def persist_search
    @search = Search.new params[:search]
  end
end

Now you'll have a Search object in all of your requests with your user's search params. Use it as you will to return them the resources they are looking for.

*Side note*
I use the above logic for all of my resources, until one of my resources has a requirement like a validation. Then I break it into something like FlightSearch:

require 'ostruct'
# ostruct for that lazy goodness
class FlightSearch < OpenStruct
  # Get activemodel in there for all its cool functionality like model name, pluralization, validation, yada yada yada
  include ActiveModel::Validations
  include ActiveModel::Conversion
  extend  ActiveModel::Naming
 
  validates_presence_of :origin_airport, :destination_airport
 
  # you can do cool things here, just make sure you call super so ostruct 
  # takes all those hash params and makes them methods
  def initialize(*args)
    super
  end
 
  # ActiveModel needs to know that this wasn't persisted.
  def persisted? ; false ; end;
end

Post to Twitter Post to Digg Post to Facebook Post to Reddit Post to StumbleUpon

17Oct/110

Airbrake’s Javascript Error Reporting and Google

So today I turned on the experimental JavaScript Error Reporting in Airbrake today. Within about 5 minutes my inbox was bombarded.

Looks like Google the masters of writing software for everything are very diligent in testing their code.

I have a feeling I'm going to have to add a lot of exclusions to my "Global Error Classes" list.

Post to Twitter Post to Digg Post to Facebook Post to Reddit Post to StumbleUpon

7Oct/110

Using devise’s scoped url helpers in Cucumber; new_registration_path, new_session_path

You can use devise's scoped url helpers from cucumber, but you have to use them by their real Url Helper method names:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
module NavigationHelpers
  def path_to(page_name)
    case page_name
    when /the sign up page/
      # dont use the helper's helper
      # new_registration_path(:user)      
 
      # use the underlying url helper
      new_user_registration_path
    when /the sign in page/
      # dont use the helper's helper
      # new_session_path(:user)      
 
      # use the underlying url helper
      new_user_session_path
    else
      #...yada, yada

Post to Twitter Post to Digg Post to Facebook Post to Reddit Post to StumbleUpon

6Oct/110

Screen shots of Steve Jobs Homage Pages, and Smarmy comments.

This is just a few screen shots of some big software companies with homages on their home pages to Steve Jobs. These are listed from Classy to Least Classy.

Apple
Apple - Steve Jobs Homage
Well of course they have one.

Google
Google - Steve Jobs Homage
Despite the phone war, classy Google - Very classy.

Adobe
Adobe - Steve Jobs Homage
Bastard wouldn't let your crappy software on his iOS, but a little reminiscent photo. *Respect*

Microsoft
Microsoft - Steve Jobs Homage
"Steve Jobs is dead, btw do you have an XBox 360 yet? Apple never made a console - Just sayin'"

Dell
Dell - Steve Jobs Homage
"Who the fuck is Steve Jobs?" Michael Dell! *Tsk, tsk* That's just rude.

Post to Twitter Post to Digg Post to Facebook Post to Reddit Post to StumbleUpon

14Apr/110

Application stuck installing on iPhone

I was trying to install an app last night while buzzed in a shady dive bar with no signal.

It took forever and eventually my phone gave up. I figured when I was on a decent network it'd continue installing. Nopecity.

Today the app has about half the meter full.

How do you fix it?

I tried clicking. Nope. Deleting? Nope - it was disabled.

Reboot the phone? Yea! It prompted me for my password and all is good.

Post to Twitter Post to Digg Post to Facebook Post to Reddit Post to StumbleUpon

12Apr/110

cucumber.yml was found, but could not be parsed. Please refer to cucumber’s documentation on correct profile usage.

Yeah, I got that message today and wasted about 30 minutes of my life.

I hadn't changed my cuke yaml file since I started work on the app.

I tried:
* upgrading cucumber (FAIL)
* using another yaml file (FAIL)
* upgrading gherkin (FAIL)
* hard reseting the branch I was on (FAIL)

Turned out to just be a bum rerun.txt file. So I deleted it.

I need a refund on that 30 minutes.

Post to Twitter Post to Digg Post to Facebook Post to Reddit Post to StumbleUpon

11Apr/110

How to stop ruby’s builder gem from escaping too much stuff (like the links in your atom feeds) :(

So, I recently started working on Dealbase and its a rails 2 site. I don't have the luxury of called #html_safe on a string to stop it from being escaped.

While working on our syndication system I came across an interesting issue where the links in our Atom feeds were getting escaped:

1
2
3
4
5
6
7
<!-- instead of -->
<link type="text/html" rel="alternate" href="http://dealbase.dev/Scottsdale-hotel-deals-discounts-457?deal=266679&foo=bar"/>
 
<!-- I was getting -->
<link type="text/html" rel="alternate" href="http://dealbase.dev/Scottsdale-hotel-deals-discounts-457?deal=266679&ampfoo=bar"/>
 
<!-- WOMP -->

So I breakpointed and started poking around:

1
2
3
4
5
6
7
8
9
10
11
atom_feed do |feed|
  feed.title("My cool feed")
  feed.updated(@items.first.try(:created_at))
 
  for item in @items
    # here was the problem... cool_item_url(item) is getting escaped... right here though, its FINE?!
    feed.entry(deal, :url => cool_item_url(item)) do |entry|
      #... yada, yada
    end
  end
end

Ok, so something is being called on it... right?
I inspect the methods on the string that gets returned from cool_item_url(item) and found an interesting one called "to_xs".

So I throw an instance_eval in there to see whats up with this method:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
atom_feed do |feed|
  feed.title("My cool feed")
  feed.updated(@items.first.try(:created_at))
  link_hack = cool_item_url(item)
  link_hack.instance_eval do
    def to_xs
      raise Exception, "STOP CALLING THIS"
    end
  end
  for item in @items
    feed.entry(deal, :url => link_hack) do |entry|
      #... yada, yada
    end
  end
end

Hit the atom feed, and boom. Exception. Yep, somethings calling it. I looked at the backtrace and its builder. After poking around I found this from the builder docs:
"String attribute values are now escaped by default by Builder (NOTE: this is new behavior as of version 2.0).
However, occasionally you need to use entities in attribute values. Using a symbols (rather than a string) for an attribute value will cause Builder to not run its quoting/escaping algorithm on that particular value."

So the fix?

To call to_sym on the link in the builder.

1
2
3
4
5
6
7
8
9
10
atom_feed do |feed|
  feed.title("My cool feed")
  feed.updated(@items.first.try(:created_at))
 
  for item in @items
    feed.entry(deal, :url => cool_item_url(item).to_sym) do |entry|
      #... yada, yada
    end
  end
end

Its ugly, but it works. Thanks builder :/

Post to Twitter Post to Digg Post to Facebook Post to Reddit Post to StumbleUpon

Filed under: Rails, Ruby No Comments
11Apr/110

Soft launch of Rebody (rebodyhq.com)

Ian Serlin and I have been working on kolaboratory's first official project for the past few months called Rebody.

Rebody is a fitness and health analytics and tracking platform. The goal is to help people lose weight like I did through setting short goals and focusing on your body's metrics so you can see what really works for you.

Beyond that Rebody will soon have a network of trusted and qualified personal trainers to look into your metrics and questions to help you determine how to "rebuild yourself", as well as a community of people sharing their results that you can browse for inspiration or to apply their methods to yourself.

We are in our soft launch right now accepting Alpha sign ups. For pre-registering you'll get the first three months for free and lock in at $9 a month for life (our competitors software starts around $25/mo).

I started my experiment today. 10% body fat here I come. Can I do it? You'll need to follow me on rebody to find out.

Post to Twitter Post to Digg Post to Facebook Post to Reddit Post to StumbleUpon

1Apr/111

Hulu’s April Fool’s Prank

If you haven't seen Hulu's April fool's prank, you are missing out.

hulu

I have to say, they had me at first, but if they really wanted to trick me they would have pretended to add some good content.

PWNED.

Post to Twitter Post to Digg Post to Facebook Post to Reddit Post to StumbleUpon

Filed under: Random 1 Comment
24Mar/110

Backdateable mongoid models – a simple little module I use a lot

I have a lot of models in one of the projects I am currently working on that need to be backdate-able. This is just a simple module I add to any class that needs to support it. It could be easily tweaked for ActiveRecord.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
module Backdateable
  module ClassMethods;end;
 
  def self.included(base)
    base.extend(ClassMethods)
    #allows this to be an accessor on the front end, although, 
    # if the date is left blank, it gets set properly in before
    base.send(:field, :backdated, type: Boolean, default: false)
    base.send(:field, :recorded_at, type: Time)
 
    if base.respond_to?(:default_scope)
      base.send(:default_scope, :asc, :recorded_at)
    end
 
    # Changing this to before_create only allows backdating on creation...
    base.send(:before_save, :set_recorded_at)
  end
 
  # defaulting recorded at to created_at lets this be sortable by recorded at
  # we override backdated here in case the date was originally left blank
  def set_recorded_at
    self[:recorded_at] ||= self[:created_at]
    self[:backdated] = (self[:recorded_at] != self[:created_at])
    true
  end
end

Now you can do:

1
2
3
4
5
6
7
8
9
10
11
class Measurement
  include Mongoid::Document
  include Mongoid::Timestamps
  include Backdateable
end
 
Measurement.create
# => created_at & recorded_at are set to the same, backdated is set to false
 
Measurement.create(:recorded_at => Time.now.advance(:days => -7))
# => recorded_at is set to the past, backdated is set to true

Why do I default recorded at to created at? So I can sort by recorded_at.

Done, son.

Post to Twitter Post to Digg Post to Facebook Post to Reddit Post to StumbleUpon

Tagged as: , , No Comments