Peter Jaros's blog



Peter JarosPeter Jaros
Does the set of all sets contain itself?
edit Posted by Peter Jaros on Tuesday April 03, 2012 at 03:26PM

No.

$ irb -r set
1.9.3p125 :001 > set = ObjectSpace.each_object(Set).to_set
 => #<Set: {#<Set: {...}>}> 
1.9.3p125 :002 > set.include?(set)
 => false 

However, the Enumeration of all Enumerations does contain itself.

1.9.3p125 :001 > e = ObjectSpace.each_object(Enumerator)
 => #<Enumerator: ObjectSpace:each_object(Enumerator)> 
1.9.3p125 :002 > e.include?(e)
 => true 

Why this is so is left as an exercise to the reader.

Peter JarosPeter Jaros
Private setters in Ruby: What to do?
edit Posted by Peter Jaros on Thursday December 22, 2011 at 06:14AM

Normally, if you have a private method, you can't call it with an explicit receiver, even if that receiver is self. So you can't say

def foo
 self.bar  # explicit receiver
end

private
def bar
  123
end

Instead, foo needs to call simply bar, leaving the self implicit:

def foo
 bar  # implicit receiver
end

However, when you call setters, you always need an explicit receiver, or you'll just assign a local variable:

def assign_things
  self.a = 123
  b = 456
end

def a=(v)
  puts "This one gets called."
end

def b=(v)
  raise "This one never does; the other method makes a local called `b` instead."
end

So, what do you do if you have a private setter? You call it with an explicit receiver:

def assign_things
  self.a = 123
end

private
def a=(v)
  puts "This is called successfully."
end

There's a crazy special exception in Ruby that lets you use an explicit receiver of self with a setter just so that you can call private setters.

This strikes me as weird. Why can't you call any private method explicitly on self? I thought it was just easier to implement Ruby if you couldn't, but if they made it work for setters, I'm not sure what the big deal is.

Peter JarosPeter Jaros
The Radically Refactored Rails Roundup
edit Posted by Peter Jaros on Sunday November 06, 2011 at 06:38PM

I want to talk about something that's been bugging me for a long time in Rails. I want to talk about it, but a lot of smart people have already said what I have to say recently. They've said it rather well.

Here's the upshot: Rails makes it look like you're supposed to have model objects (subclasses of ActiveRecord::Base), controller classes (subclasses of ActionController::Base), and view templates, and that's it. Maybe some observers (subclasses of ActiveRecord::Observer). For the most part, Rails style is to push as much behavior into the model as possible. "Skinny controllers, skinny views, fat models," they said.

Well, object obesity is a growing problem in the Rails world, because we've been shoving so much responsibility on our poor model objects that they can barely hold themselves up. They're particularly hard to test, because while you're mainly interested in testing your domain logic, to make one of these objects in a test you often need to persist it in the database first. That's just crazy. And slow.

Rails is no more exempt from the utility of the Single Responsibility Principle than any other environment. What if we separated the concerns of domain logic and persistence?

For a while I thought I might be the crazy one, but it turns out I'm not alone in thinking this. We're seeing a renaissance of classical OO patterns in the Rails world as people realize that throwing everything in a handful of objects doesn't scale with application complexity.

The Roundup

  • The earliest post I've seen is from James Golick in early 2010, who calls it Crazy, Heretical, and Awesome. As James writes,

    Ever wondered why it seems impossible to write a really good state machine plugin — or why file uploads always seem to hurt eventually, even with something like paperclip? It's because these things don't belong coupled to persistence. [...] A file upload handler shouldn't have to worry about how the name of the file gets stored to the database, let alone where it is in the persistence lifecycle and what that means. Are we in a transaction? Is it before or after save? Can we safely raise an error?

    I also love the objection he hears the reader raise:

    "But then I'll have all these extra classes in my app!"

    I've heard this objection too. I don't get it. Some people seem to have the idea that the fewer classes you have, the easier it is to maintain the app. Maybe it comes from being used to 3000-line classes. Having more of those would be a pain. But by breaking up responsibility into cohesive units, each class becomes comprehensible, which is of the utmost importance in software development, especially as the complexity of the app and the size of the team grow.

  • This past July, the storm began to gather, as Avdi Grimm got all Fowler on Rails' ass. He also gives a shout out to Jeff Casimir's Draper, which I haven't gotten to use yet but I am itching to try. People who have used it are saying good things.

  • Then Piotr Solnica wrote about "Making ActiveRecord Models Thin". Don't miss the rich discussion in the comments. Also, make sure you read the section "Well Defined API". The part where he writes,

    Your Domain Model should have an interface to every action your application should be able to perform. If you have an online shop where a user can buy a product then with a well-written Rails application you should be able to fire up the console and be able to easily perform this operation. If it’s not so simple then you probably want to think about your model implementation again.

    Mmm, yeah. That's good medicine.

  • Coming out of that discussion in the comments, Giles Bowkett re-raised a point from James' piece, that not all apps will need this kind of treatment, because not all apps will be complex enough to feel the pain. Giles writes,

    I don't think there's really any debate here at all, except for one crucial question: where do you mark the threshold? How do you decide when your code needs this split?

    Great question.

  • Next up, the great Steve Klabnik calls Plain Old Ruby Objects "The Secret to Rails OO Design", focusing on the ways they can improve the structuring of view logic. He explains the problem with Rails this way:

    [T]here’s something special about Rails which seems to lure you into the trap of never breaking classes down. Maybe it’s that lib/ feels like such a junk drawer. Maybe it’s that the fifteen minute examples only ever include ActiveRecord models.

    He followed that post up with another awesome one about writing presenters. Do give them a read.

Any good articles I've missed? Leave a comment and let me know.

Peter JarosPeter Jaros
NYC Standup 9/14/2011: How much is that Capybara in the window?
edit Posted by Peter Jaros on Wednesday September 14, 2011 at 01:45PM

(Or vice versa.)

Ask for Help

"How can we control popup windows when we're testing with Capybara?"

See the method within_window.

"How can I stub the current_user in a helper spec?"

Try stubbing #current_user on the helper object in the spec.

Interesting

In your AR model, if you do this

after_update :do_foo, :if => :bar_changed?
after_update :do_foo, :if => :qux_changed?

The method #do_foo will only be called after an update where qux has changed, not one where only bar has changed. The callbacks are keyed by the methods they call, so the second callback overwrites the first one entirely.

Peter JarosPeter Jaros
NY Standup 7/19/2011: Fruit Rollups
edit Posted by Peter Jaros on Tuesday July 19, 2011 at 12:59PM

Interesting Things

  • Two-Subject Monte: Consider the following RSpec code:

    describe "fruit" do
      let(:subject) { "banana" }
      context "rounder" do
        subject { "orange" }
        it { should == "orange" }
      end
    end
    

    Does it pass? The answer is no. The implicit subject evaluates to "banana" from the let(:subject) { } at the top, and is not overridden by the subject { } later on. This can be considered a bug in RSpec, but it's also pretty weird to assign subject with let(). This was a mistake which RSpec should probably warn you about.

  • CSV fixtures are gone in Rails Edge, and will presumably be gone in 3.1. No announcement of this is available at press time, but the code for it is gone. Incidentally, CSV fixtures also don't preserve whitespace at the beginning or end of each of your values. If you're using them, this would be a great time to move to YAML fixtures.

Peter JarosPeter Jaros
NY Standup 6/15/2011: Time keeps on slippin' into the future.
edit Posted by Peter Jaros on Wednesday June 15, 2011 at 02:05PM

Interesting Things

  • According to Newlee, a the name of a polymorphic belongs_to can't end in a digit. That is, you can't say,

    belongs_to :johnny_5, polymorphic: true
    

    without some very strange errors from Rails.

  • Chronic is a seriously awesome natural-language date/time parser for Ruby. If you're on Ruby 1.9 and have been missing it, today's a day to celebrate! Chronic is now fully Ruby 1.9 compatible.

Peter JarosPeter Jaros
NY Standup 6/10/2011: Action-packed gemsets!
edit Posted by Peter Jaros on Friday June 10, 2011 at 09:21AM

Interesting Things

  • Reputedly, the webserver G-WAN offers you 2x the speed of nginx for delivering static files.

  • Case Commons and the Casebook team is proud to announce (an early version of) ActiveTable. In the spirit of ActiveHash, ActiveTable lets you store enumeration-style data in your source code and access it with an ActiveRecord-like interface. ActiveTable, however, uses temporary tables to store the data in each database connection, allowing you to use it in SQL queries and joins. Props go to Todd Persen for making it happen.

Events

  • Today is Walkabout NYC, a city-wide tech startup open house. It's part of this year's Internet Week NY. From 12pm to 6pm tech shops throughout NYC will open their doors to visitors who want to see how it all works. Pivotal's participating, so stop by and see how we do what we do!

Peter JarosPeter Jaros
NY Standup 6/9/2011: Need for speed, revisited.
edit Posted by Peter Jaros on Thursday June 09, 2011 at 11:26AM

Interesting Things

  • Last week, we discovered that Ruby 1.9's require is unnecessarily slow, and that there's a patch targeted for 1.9.3. Until then, Dave G. says, you can use the following to patch your Ruby 1.9.2 using RVM:

    curl https://raw.github.com/gist/1008945/7532898172cd9f03b4c0d0db145bc2440dcbb2f6/load.patch > /tmp/load.patch
    rvm get head   # always good to make sure you're up to date with RVM
    rvm reload
    rvm install ruby-1.9.2-p180 --patch /tmp/load.patch -n patched
    rvm use ruby-1.9.2-p180-patched
    

    [from https://gist.github.com/1008945/]

Events

Peter JarosPeter Jaros
NY Standup 6/8/2011: Won't get fooled again.
edit Posted by Peter Jaros on Thursday June 09, 2011 at 10:21AM

Ask for Help

"How can I validate the presence of a boolean field?"

false.present? is false, so validates :a_boolean_field, presence: true will not cause a validation error when the field's value is false. What you're really trying to do, probably, is to validate that it's not nil.

The best solution we had was to use validates :a_boolean_field, inclusion: { in: [true, false], message: "must be specified" }. The custom message is needed because the default inclusion message looks weird to the user here.

How can we integration-test CarrierWave uploads to S3? Can we stub out S3?

Two suggestions: use VCR to mock the S3 conversation or use Park Place to provide a fake S3 and check the results afterwards.

Interesting Things

  • Given a Rails belongs_to association reflection, how do you get the name of the foreign key column? It's not what you might think:

    class Person < ActiveRecord::Base
      belongs_to :best_friend, class_name: "Person"
    end
    
    
    Person.reflect_on_association(:best_friend).primary_key_name  # => "best_friend_id"
    

    Why is it called primary_key_name if it's a foreign key? No idea. But it is.

    Note: The reflection also has an association_foreign_key. This is not what it's for. In this case, for instance,

    Person.reflect_on_association(:best_friend).association_foreign_key  # => "person_id"
    

Peter JarosPeter Jaros
NY Standup 6/7/2011: Making the cut.
edit Posted by Peter Jaros on Wednesday June 08, 2011 at 07:21AM

Interesting Things

  • min_by / max_by: Ian points us towards Enumerable's handy #min_by and #max_by. Want to get the string in a collection whose second-to-last character is earliest in the alphabet?

    ["ayx", "zbaaaz"].min_by { |s| s[-2] }  # => "zbaaaz"
    
  • keep_if: On the subject of collections, Kris points out Ruby 1.9's Array#keep_if (note the missing bang at the end), which mutates the array to remove things for which the block returns false. For example,

    a = ["ayx", "zbaaaz"]
    a.keep_if { |s| s.length < 4 }
    a                                       # => ["ayx"]
    

    Another method, Array#select! behaves very similarly. The only difference is that when it doesn't change the array, #select! returns nil while #keep_if returns the array. Returning nil matches the behavior of other mutators like String#sub!, while #keep_if breaks the pattern. Thus,

    ["ayx", "zbaaaz"].keep_if { |s| s.length < 4 }    # => ["ayx"]
    ["ayx", "zbaaaz"].select! { |s| s.length < 4 }    # => ["ayx"]
    ["ayx", "zbaaaz"].keep_if { |s| s.length < 10 }   # => ["ayx", "zbaaaz"]
    ["ayx", "zbaaaz"].select! { |s| s.length < 10 }   # => nil
    

    It is, perhaps, of questionable value.

  • $("textarea").clone(): Ian discovered that when jQuery clones form fields, the clones of input elements retain the values of the originals, while textareas and selects become blank.

  • jsFiddle: Sam J. points us towards jsFiddle, a nifty tool for sharing JavaScript snippets. It provides a pane each for JS, CSS, and HTML, and then a pane that shows the results. Then you can share it like a Gist or a Pastie.

Other articles: