Skip to content

Instantly share code, notes, and snippets.

@dbrady
Created July 7, 2011 18:25
Show Gist options
  • Save dbrady/1070178 to your computer and use it in GitHub Desktop.
Save dbrady/1070178 to your computer and use it in GitHub Desktop.
Get ActiveRecord object from object_or_id argument
class StoreProductCollaborator
def initialize(product_or_id, store_or_id)
# I use this pattern everywhere. I would like to abstract it, but
# can't think of a good name for the abstraction.
@product = Product.find(product_or_id) unless product_or_id.is_a? Product
@store = Store.find(store_or_id) unless store_or_id.is_a? Store
end
# Intended usage examples:
# sp1 = StoreProductCollaborator.new(42, 13)
# sp2 = StoreProductCollaborator.new(@product, @store)
# sp3 = StoreProductCollaborator.new(42, @store)
# sp4 = StoreProductCollaborator.new(@product, 13)
# ...I can even see the shape in my mind of this code, and its
# value as an abstraction: if we called it foo_snark(klass) and put
# it on Integer AND on ActiveRecord::Base, then Integer could find
# the object, and ActiveRecord::Base could check to make sure that
# the AR object given matches the expected class.
#
# But seriously, what to call it? instantiate? to_model?
# to_model_instance?
end
@jtanner
Copy link

jtanner commented Jul 7, 2011

In a project at LMP we have a helper method on ActiveRecord::Base that does something similar. We use [] for the method, for example:

Product[@Product] # => just returns @Product
Product[1] # => calls Product.find(1)

@JohnFord
Copy link

JohnFord commented Jul 7, 2011

I'm sure I'm missing something. Can you elaborate on this foo_snark'ness? By the way, this is similar to how I usually do this:

class StoreProductCollaborator
  def initialize(product_or_id, store_or_id)
    @product = Product.for(product_or_id)
    @store = Store.for(store_or_id)
  end
end

class Store < ActiveRecord::Base
  def self.for(store_or_id)
    return store_or_id if store_or_id.is_a? Store
    find(store_or_id)
  end
end

class Product < ActiveRecord::Base
  #...
end

@geeksam
Copy link

geeksam commented Jul 7, 2011

@jtanner: Interesting, but the square brackets remind me of array/hash access first, and Proc#call second. Why not Product(@Product) or Product(1), in keeping with the Array, Complex, Float, Integer, Rational, and String methods in Kernel?

@geeksam
Copy link

geeksam commented Jul 7, 2011

dbrady: my first guess at a name would be "modelizing," but as I look at it, it's basically a fancy typecast:
"Take something that's an object, or an identifier for an object, and give me back an object." I'd say "to_model" is a pretty good name for that.

@jtanner
Copy link

jtanner commented Jul 7, 2011

@geeksam, that's a great idea.

@dbrady
Copy link
Author

dbrady commented Jul 7, 2011

jtanner: Ah, yes, I remember that. That's essentially shorthand for .find(), though, isn't it? Or would Product[Product.new] still return the new product object?

geeksam: Excellent! I like Store.for but in our fixation on (integer or store).for(Store), we hit on "to_model" as well. Great minds think alike (or perhaps fools seldom differ?)

Thanks, both!

@geeksam
Copy link

geeksam commented Jul 7, 2011

@dbrady: Surely the former. I am constantly astonished at the variety of foolishness available. ;>

@dbrady
Copy link
Author

dbrady commented Jul 7, 2011

jtanner: nevermind, you said the thing I asked apparently I can't read.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment