tags:

views:

46

answers:

4

I am creating a web application to integrate with Chargify. I want to return a hash with customer_id set if the user has a customer associated with the account, and customer_attributes if a customer has to be created.

Is there any way that I could do this with an if..end block inside of the hash definition. For example, I would be wanting to do something like the following (does not work):

def subscription_params(product_id)
  {
    :product_id => product_id,
    if customer_id.nil?
      :customer_attributes => customer_params,
    else
      :customer_id => customer_id,
    end
    :credit_card_attributes => credit_card_params
  }
end
+2  A: 

Tried the ternary operator?

Azeem.Butt
This won't work as the value __and__ the key for the item is going to be changed based on the condition.
Benjamin Manns
+1  A: 

While you can specify a single value using :key => if bool then val1 else val2 end, there's no way to use an if statement to choose whether to insert a key-value pair while in a literal hash.

That being said, you could use the oft-overlooked Object#tap method available in Ruby 1.8.7 and Ruby 1.9+ to conditionally insert values into the hash:

irb(main):006:0> { :a => "A"}.tap { |h| if true then h[:b] = "B" end }.tap { |h| if false then h[:c] = "D" end }
=> {:b=>"B", :a=>"A"}
Mark Rushakoff
It's not as much overlooked as new to Ruby 1.9, and will not work on pre-1.9.
vladr
Except it's in 1.8.7 like I said above. http://www.sfr-fresh.com/unix/misc/ruby-1.8.7-p249.tar.gz:a/ruby-1.8.7-p249/NEWS
Mark Rushakoff
OK, Ruby 1.8.7 patch level 249 :) -- which, granted, should be available on *most* systems out there by now.
vladr
+3  A: 

Use Hash.merge to conditionally merge one set (or another) of key-value pairs:

def subscription_params(product_id)
  {
    :product_id => product_id,
    :credit_card_attributes => credit_card_params
  }.merge(customer_id.nil? ?
    { :customer_attributes => customer_params } :
    { :customer_id => customer_id }
  )
end
vladr
A: 

The idiomatic way to do this is to take advantage of default nil values in hashes.

> myHash = {:x => :y}  # => {:x=>:y}
> myHash[:d]           # => nil

So, you can set either :customer_id or :customer_attributes, no if statement required, and later test for which one is present. You might give preference to :customer_id, when you do this.

unless purchase[:customer_id].nil?
  @customer = Customer.find(purchase[:customer_id])
else
  @customer = Customer.create!(purchase[:customer_attributes])
end
Andres Jaan Tack