Dr Nic

map_by_method now works with ActiveRecord associations

I was always annoyed that map_by_method was broken for ActiveRecord has_many associations. 6 mths later I finally fixed it.

That’s the magic of Open Source Software. [/end sarcasm]

So now, the following example works like it should:

$ gem install map_by_method
$ console
> require 'map_by_method'  # stick this in your environment.rb for Rails
> user = User.find_by_name "Dr Nic"
> user.companies.map_by_name
=> ['Dr Nic Academy', 'Dr Nic Institute of Being Silly']
> user.companies.map_by_id_and_name
=> [[1, 'Dr Nic Academy'], [9, 'Dr Nic Institute of Being Silly']]

Recap: why use map_by_method?

Try the following example:

> user.companies.map_by_employees.flatten
=> list of all employees of user

Versus:

> user.companies.map { |company| company.employees}.flatten
or
> user.companies.map(&:employees).flatten

Or compare:

> user.companies.map_by_id_and_name
=> [[1, 'Dr Nic Academy'], [9, 'Dr Nic Institute of Being Silly']]

Versus:

> user.companies.map { |company| [company.id, company.name]}

That is, it looks and feels just like ActiveRecord’s #find method, with its find_by_first_name_and_last_name magic.

Summary

No {, }, |, &, or : required. Just clean method names.

Bonus other gem

In the spirit of ActiveRecord hacks, there is to_activerecord:

$ gem install to_activerecord
$ console
> require 'to_activerecord'  # stick this in your environment.rb for Rails
> [1,2,3].to_user
=> [list of User with id's 1,2,3]

To me, this suffix operator reads cleaner than the traditional:

> User.find([1,2,3])

For example, if you want to perform an operation on the list of Users:

> ids = [1,2,3]
> ids.to_user.map_by_name
=> ['Dr Nic', 'Banjo', 'Nancy']

Versus:

> User.find(ids).map_by_name

Related posts:

  1. Find objects in IRB directly from browser URLs A long time ago, I tired of going into the...
  2. map_by_method – the final announcement I don’t really talk about my projects after I release...
  3. MagicCGI shows OpenID user count In the last 20 days, 43 people have used...
  4. Welcome to the future Welcome to anyone visiting from DHH’s blog and other corners...
  5. “Drop Rails into TomCat and it just works” – Ola Bini on JRuby presentation Until Ola Bini stood up at the Stockholm Rails/Ruby Group...

22 Responses to “map_by_method now works with ActiveRecord associations”

  1. pangel says:

    I am not convinced !

    user.companies.map(&:employees).flatten
    

    versus

    user.companies.map_by_employees.flatten
    

    I do not see such a difference compared to the method_missing time we lose here.

  2. Dr Nic says:

    [start jedi mind trick] That’s not the example you are looking for[/end trick]

    I agree that example isn’t the best, so how about this one:

    user.companies.map_by_id_and_name_and_employees
    

    The Symbol.to_proc cannot be used here, so you are left with:

    user.companies.map {|company| [company.id, company.name, company.employees}
    
  3. I’d also argue that:

    >> user.companies.map_by_employees.flatten
    

    is more readable and concise than:

    >> user.companies.map(&:employees).flatten
    

    Readability is higher in book any day.

    Great work once again Dr.Nic!

  4. dies-el says:

    ‘map_by_id_and_name’ looks made for the select form helper. One less model-method to hand make!

    Nice one!

  5. bryanl says:

    good stuff. i was looking for magic like this just the other day.

  6. chris says:

    Great stuff, as always. Just wanted to point out that “map_by_method” link in the first line of your post, is broken.

  7. Dr Nic says:

    @chris [via] – ok, I’ve fixed the link, but just to make sure, can you click the links harder next time?

  8. Vann says:

    Nic,

    Is there something going on with map_by_method and ActionController For some reason it looks like any of my RESTful actions are failing; even if I don’t require ‘map_by_method’ in the environment. I get something like :

    NoMethodError (undefined method `to_str’ for [:action, "index"]:Array):
    /usr/local/lib/ruby/gems/1.8/gems/map_by_method-0.7.0/lib/map_by_method.rb:12:in `method_missing’
    /usr/local/lib/ruby/gems/1.8/gems/actionpack-1.13.3/lib/action_controller/layout.rb:241:in `to_s’
    /usr/local/lib/ruby/gems/1.8/gems/actionpack-1.13.3/lib/action_controller/layout.rb:241:in `render_without_benchmark’
    /usr/local/lib/ruby/gems/1.8/gems/actionpack-1.13.3/lib/action_controller/benchmarking.rb:50:in `render’

    Or does it somehow extend Array that ActionController doesn’t like? As great as it would’ve been to use it, I had to uninstall 0.7.0, sorry… let me know if you want to see of the rest of the log….

  9. Dr Nic says:

    @Vann [via] – I noticed a similar problem around the active_record_store.rb just a little while ago. I’ll post an update when I fix it. My initial thought is that its the added #respond_to? method in 0.7. Anyway, still investigating.

    So much magic in so many places.

  10. Dr Nic says:

    @Vann [via] – as for “even if I don’t require ‘map_by_method’” – you might have this in your .irbrc file perhaps.

  11. Vann says:

    @dr nic …I actually do have it in my .irbrc file, I’ll remove it from there and let you know if anything is fixed. But does it matter unless you run anything in the console?

  12. [...] map_by_method now works with ActiveRecord associations. [...]

  13. renek says:

    @Dr Nic [via]
    -
    Great module Dr Nic!

    I only had some trouble with the regex for the ‘respond_to?’ method.
    The regex in map_by_method_regex is:

    /(map|collect|select|each|reject)(_by)?_([\w\_]+\??)/

    which does (unfortunately) also match ‘each_pair’. This caused some trouble in my app since an array responds to a method that belong to hashes. Removing the ‘?’ after ‘(_by)’ in the regex works for me.

  14. Bug says:

    @Dr Nic [via] – Yeah, ok, but only in Rails does this make a difference. It seems pretty specific to the Rails domain of homogeneous arrays of model objects, readable-as-English code, and the need for blazing-fast development.

    With those as givens, of course, this is pretty neat.

  15. btucker says:

    Any progress on the issue reported by Vann above? Ran into this too, and had to downgrade back to 0.6.0.

  16. mike says:

    Symbol#to_proc can also be used with all the enumerable methods that take blocks, like sort_by and select.

  17. Dr Nic says:

    @mike [via] – true, I need to explicitly add them into the map_by_method code for them to work.

  18. Dr Nic says:

    Regarding the 0.7.0 issue with Rails, its something to do with the respond_to? method I added. I’m still to investigate.

  19. Dr Nic says:

    All known issues are resolved in 0.8.1. Thxs to Mislav Marohnić for hunting down some of the issues!

  20. Dr Nic says:

    Except the each_pair issue. I’ll investigate this later.

  21. Dr Nic says:

    map_by_method 0.8.2 should fix the each_pair issue

  22. [...] map_by_method now works with ActiveRecord associations [...]