Могу ли я поместить некоторую форму блоков If..End в определение хеша?

Я создаю веб-приложение для интеграции с Chargify. Я хочу вернуть хэш с набором customer_id, если у пользователя есть клиент, связанный с учетной записью, и customer_attributes, если клиент должен быть создан.

Есть ли способ сделать это с блоком if..end внутри определения хеша. Например, я хотел бы сделать что-то вроде следующего (не работает):

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

person Benjamin Manns    schedule 06.04.2010    source источник


Ответы (4)


Используйте Hash.merge для условного слияния одного (или другого) набора ключей- пары значений:

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
person vladr    schedule 06.04.2010

Пробовали тернарный оператор?

person Azeem.Butt    schedule 06.04.2010
comment
Это не сработает, так как значение и ключа для элемента будет изменено в зависимости от условия. - person Benjamin Manns; 06.04.2010

Хотя вы можете указать одно значение с помощью :key => if bool then val1 else val2 end, нет возможности использовать оператор if, чтобы выбрать, следует ли вставлять пару ключ-значение в литеральный хэш.

При этом вы можете использовать часто упускаемый из виду Object#tap метод, доступный в Ruby 1.8.7 и Ruby 1.9+, для условной вставки значений в хеш:

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"}
person Mark Rushakoff    schedule 06.04.2010
comment
Его не так часто упускают из виду, как новый для Ruby 1.9, и он не будет работать в версиях до 1.9. - person vladr; 06.04.2010
comment
За исключением того, что это в 1.8.7, как я сказал выше. sfr-fresh.com/unix/misc/ruby-1.8.7-p249.tar.gz:a/ - person Mark Rushakoff; 06.04.2010
comment
Итак, патч Ruby 1.8.7 уровня 249 :) -- который, само собой разумеется, уже должен быть доступен на большинстве существующих систем. - person vladr; 06.04.2010

Идиоматический способ сделать это — воспользоваться нулевыми значениями по умолчанию в хэшах.

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

Таким образом, вы можете установить либо :customer_id, либо :customer_attributes, оператор if не требуется, а позже проверить, какой из них присутствует. Вы можете отдать предпочтение :customer_id, когда делаете это.

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