Simplify multiple nil checking in Rails

后端 未结 10 1957
一个人的身影
一个人的身影 2020-12-17 06:44

How should I write:

if @parent.child.grand_child.attribute.present?
  do_something

without cumbersome nil checkings to avoid exception:

相关标签:
10条回答
  • 2020-12-17 07:26

    I suppose you can do it using a delegate method as a result you'll have sth like

    @parent.child_grand_child_attribute.present?
    
    0 讨论(0)
  • 2020-12-17 07:28

    Rails has object.try(:method):

    if @parent.try(:child).try(:grand_child).try(:attribute).present?
       do_something
    

    http://api.rubyonrails.org/classes/Object.html#method-i-try

    0 讨论(0)
  • 2020-12-17 07:28

    All these answers are old, so I thought I should share more modern options.

    If you are getting an association that might not exist:

    @parent&.child&.grand_child&.attribute
    

    if you are reaching into a hash for a key that might not exist:

    hash = {
     parent_key: {
       some_other_key: 'a value of some sort'
     },
     different_parent_key: {
       child_key: {
         grand_child: {
           attribute: 'thing'
         }
       }
     }
    }
    hash.dig(:parent_key, :child_key, :grandchild_key)
    

    Either of these will gracefully return nil if child, grandchild, or attribute don't exist

    0 讨论(0)
  • 2020-12-17 07:30

    For fun, you could use a fold:

    [:child, :grandchild, :attribute].reduce(@parent){|mem,x| mem = mem.nil? ? mem : mem.send(x) } 
    

    but using andand is probably better, or ick, which I like a lot and has methods like try and maybe.

    0 讨论(0)
  • 2020-12-17 07:34

    You can slightly reduce it by assigning the intermediate values to some local variable:

    if a = @parent.child and a = a.grandchild and a.attribute
    
    0 讨论(0)
  • 2020-12-17 07:34

    You coult just catch the exception:

    begin
      do something with parent.child.grand_child.attribute
    rescue NoMethodError => e
      do something else
    end
    
    0 讨论(0)
提交回复
热议问题