A nicer way to join my hash?


#1

I know this is dodgy, what would be a nicer way of getting all the
unique Volunteer emails that aren’t blank (or nil) and putting them in a
comma separated list?

Also, my tests seem to have come up okay, but I’m still not certain-
will my condition exclude both “” and nil?

@message = Message.new(params[:message])
volunteers = Volunteer.find(:all, :conditions => [ "email != ?", ""

], :group => “email” )
recipients = []
volunteers.each do |volunteer|
recipients << volunteer.email
end
@message.recipients = recipients.join(", ")


#2

SQL uses <>, not !=

Blog: http://random8.zenunit.com/
Learn rails: http://sensei.zenunit.com/

On 04/02/2009, at 4:24 PM, Darren J.
<removed_email_address@domain.invalid


#3

Hi,

@message = Message.new(params[:message])
@message.recipients = Volunteer.all(:conditions => “email IS NOT NULL
AND email <> ‘’”, :group => “email”).map{|v| v.email}.join(", ")


#4

No, &: is much slower and uglier

Blog: http://random8.zenunit.com/
Learn rails: http://sensei.zenunit.com/

On 04/02/2009, at 5:57 PM, Joshua A.
<removed_email_address@domain.invalid


#5

Or even this:

@message = Message.new(params[:message])

volunteers = Volunteer.all(:conditions => “email IS NOT NULL AND email
<> ‘’”, :group => “email”)

essentially the same as .map { |v| v.email } only letting ruby figure

out the “v” part.
@message.recipients = volunteers.map(&:email)

– Josh
http://iammrjoshua.com

Julian L. wrote:

Hi,

@message = Message.new(params[:message])
@message.recipients = Volunteer.all(:conditions => “email IS NOT NULL
AND email <> ‘’”, :group => “email”).map{|v| v.email}.join(", ")


#6

Julian L. wrote:

@message = Message.new(params[:message])
@message.recipients = Volunteer.all(:conditions => “email IS NOT NULL
AND email <> ‘’”, :group => “email”).map{|v| v.email}.join(", ")

Whoa… cool… I’m gonna read up on Ruby basics, thanks heaps.


#7

You might want rails basics, coz that contains SQL, ruby AND rails code

Blog: http://random8.zenunit.com/
Learn rails: http://sensei.zenunit.com/

On 04/02/2009, at 6:57 PM, Darren J.
<removed_email_address@domain.invalid


#8

It can use IS NOT NULL too


#9

You might want rails basics, coz that contains SQL, ruby AND rails code

I’ve bought and read Simply Rails 2, taught me a bit but my problem now
is that Rails is so easy that often you can get all of the functionality
you need in an app without getting into any thought-provoking Ruby
programming. If I run into a wall I just hit up Google or you guys-
which isn’t really ‘teaching’ me. :slight_smile:


#10

Actually it MUST if you’re doing not null queries. <> won’t work for
null

Blog: http://random8.zenunit.com/
Learn rails: http://sensei.zenunit.com/


#11

Project Euler!

Blog: http://random8.zenunit.com/
Learn rails: http://sensei.zenunit.com/

On 04/02/2009, at 7:40 PM, Darren J.
<removed_email_address@domain.invalid


#12

Julian,

Have you done any benchmark testing on using the &: method? I would be
curious as to why you say it’s slower.

As for uglier - I think that’s a personal preference. I personally would
never recommend chaining 3 methods together as you did for fear that one
would fail causing the infamous “undefined method … for nil”. To my
eyes, the map.(&:email) is very clean and easy to read without a bunch
of nasty |v| v.email, etc.

I would be curious about performance tests though since you say it’s
slower. I haven’t noticed any major performance hit, but I’ve never
really tested.

– Josh
http://iammrjoshua.com

Julian L. wrote:

Actually it MUST if you’re doing not null queries. <> won’t work for
null

Blog: http://random8.zenunit.com/
Learn rails: http://sensei.zenunit.com/


#13

On Feb 4, 2009, at 9:14 AM, Joshua A. wrote:

Have you done any benchmark testing on using the &: method? I would be
curious as to why you say it’s slower.

PMFJI… As I recall, the &:foo notation is a shortcut for
Symbol#to_proc so the following code snippets are the same:

def frazzle
self.name.split(//).sort_by{rand}.join(’’)
end

@stuff.each(&:frazzle)

@stuff.each{|s| Proc.new{|*args| args.shift.send(s, *args)}}

Look in active_support/symbol.rb

So what could make this slower are the facts that 1) you are creating
a new anonymous proc for each iteration through the @stuff collection;
and 2) you are using the send method to invoke the method referenced
by the symbol. Contrast that to:

@stuff.each{|s| s.frazzle}

In this case, the method is being invoked directly, skipping the steps
of creating the anonymous proc and then invoking “frazzle” via a send.

So, that’s how I understand it. Now, in the case where you have a
dozen users returned and want to list their names next to checkboxes,
the performance difference is negligible. It’s the case where you
can’t predict the size of the result set that you want to beware of.


#14

hi there,

@message.recipients = Volunteer.all(
:select => “DISTINCT email”,
:conditions => “email IS NOT NULL AND email <> ‘’”).map(&:email).join
(", ")

I think one line like that would work for you.
(You don’t need to use the shortcut symbol to proc if you don’t like
it)

cheers
Regedor


#15

Undefine methodcan be caught with rescue ‘default’ on the end. No
biggie.

Blog: http://random8.zenunit.com/
Learn rails: http://sensei.zenunit.com/

On 05/02/2009, at 4:14 AM, Joshua A.
<removed_email_address@domain.invalid


#16

Steve,

Great explanation! Thanks!

– Josh
http://iammrjoshua.com

Steve R. wrote:

On Feb 4, 2009, at 9:14 AM, Joshua A. wrote:

Have you done any benchmark testing on using the &: method? I would be
curious as to why you say it’s slower.

PMFJI… As I recall, the &:foo notation is a shortcut for
Symbol#to_proc so the following code snippets are the same:

def frazzle
self.name.split(//).sort_by{rand}.join(’’)
end

@stuff.each(&:frazzle)

@stuff.each{|s| Proc.new{|*args| args.shift.send(s, *args)}}

Look in active_support/symbol.rb

So what could make this slower are the facts that 1) you are creating
a new anonymous proc for each iteration through the @stuff collection;
and 2) you are using the send method to invoke the method referenced
by the symbol. Contrast that to:

@stuff.each{|s| s.frazzle}

In this case, the method is being invoked directly, skipping the steps
of creating the anonymous proc and then invoking “frazzle” via a send.

So, that’s how I understand it. Now, in the case where you have a
dozen users returned and want to list their names next to checkboxes,
the performance difference is negligible. It’s the case where you
can’t predict the size of the result set that you want to beware of.