1

The following statements need to be evaluated if their content is not nil and submitted. The receiving end does not accept nil values.

  :customer => {
    if [email protected]? :first_name => @transaction.nome,
    if [email protected]_name.nil? :last_name => @transaction.last_name,
    if [email protected]_id.nil? :country_name => @transaction.nation.name
    },

Without the condition a simple statement :first_name => @transaction.nome, is properly evaluated and the syntax with brackets and commas is proper. However, the introduction of the condition creates blanks in cases of nil values and generates a syntax error unexpected '}'.

How can this be overcome?

3 Answers 3

1

You can simply add the values and later filter them out. Will save you from all those checks:

:customer => {
    :first_name => @transaction.nome,
    :last_name => @transaction.last_name,
    :country_name => @transaction.nation.try(:name)
 }.reject{ |_, v| v.nil? }
Sign up to request clarification or add additional context in comments.

8 Comments

I believe to have successfully implemented this with a minor variant: take into account empty values .reject{ |_, v| (v.nil? || v.empty?) }. Hit a different snag on the other end so will delay in fully confirming. I appreciate the conciseness of the approach
This code doesn't seem to work for the OP's question code. When transaction.nation_id is nil, then transaction.nation won't be found, then transaction.nation.name will raise an exception.
@joelparkerhenderson Makes sense. Used try to see if name can be fetched, returns nil otherwise.
Still doesn't work. I think you want try(:nation) instead of try(:name).
@joelparkerhenderson No. It should. if @transaction.nation is nil, calling try(:name) on that will always return nil. @transaction.nation will never raise an exception; if association doesn't exist, it will only give nil.
|
1

One way is to build the hash:

h = {}
if @transaction.name      !=nil then h[:first_name]   = @transaction.name        end
if @transaction.last_name !=nil then h[:last_name]    = @transaction.last_name   end
if @transaction.nation_id !=nil then h[:country_name] = @transaction.nation.name end
:customer => h

If you know that your items are always truthy or nil, never falesy, then this is shorter:

if @transaction.name      then h[:first_name]   = @transaction.name        end
if @transaction.last_name then h[:last_name]    = @transaction.last_name   end
if @transaction.nation_id then h[:country_name] = @transaction.nation.name end

9 Comments

I guess I miscommunicated something. The nil element should not generate a hash component. As it is, I'm passing along a nil value which is not acceptable to the receiver
The code above does not pass along a nil value. Each line says "Is this value nil? If so, do not add it to hash".
Trailing conditions are often confusing, especially the sort that lean heavily on the loose-binding or.
@tadman Ok I'll update; what do you like best for the syntax?
"Surprise conditions" of any sort usually trip people up. What looks like an assignment is actually rendered conditional by the clause at the end, confusing what's actually happening, so whenever possible, just spell it out directly with a leading if. In this case a mapping table would reduce the number of if statements required. Additionally, comparing != nil is usually pointless unless you're worried about distinguishing between nil and false, a very uncommon case.
|
1

You could kill some duplication by adding a small lambda

customer: {}.tap { |h|
  conditional_store = -> key, value { h.store(key, value) unless value.nil? }
  conditional_store[:firstName,    @transaction.name]
  conditional_store[:last_name,    @transaction.last_name]
  conditional_store[:country_name, @transaction.nation.name]
}

5 Comments

Would probably be better expressed as a function of some kind rather than an inline lambda, but this is the right idea.
This code doesn't work for the OP's question because this code doesn't handle the @transaction.nation.name item.
@joelparkerhenderson updated. You could potentially make a case for monkey patching a method onto Hash to do this but this is simple enough
@tadman are you suggesting the whole value for customer: should be wrapped behind a method or the conditional_store lambda should be some kind of method?
I mean if this is going to be used more than once, a first-class utility method with the same name would be better than a hidden lambda. Everything else looks good.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.