Rails try method

Posted by wxianfeng Thu, 13 Jan 2011 19:20:00 GMT

环境:ruby 1.9.2 + rails 3.0.3

我们经常会有这样的操作:

user = User.find_by_login("wxianfeng")  # =>  nil 
user.name # => NoMethodError: undefined method `name' for nil:NilClass

假如 login 为 wxianfeng 不存在 ,会报错:

NoMethodError: undefined method `name' for nil:NilClass

那么建议使用 try 方法避免报错,try 返回的是 nil

user.try(:name) # =>nil 

也就相当于

nil.try(:name) # => nil

看下源码: here

其实就是调用了 __send__ 方法 , __send__ 方法 和 send 方法等价 , 只不过 __send__ 方法 为了防止 有已经存在的 send 方法 , nil 的话 调用 NilClass 的 try 方法

另外 发现 github上 try方法已经重新写了 ,如下: here

class Object
  # Invokes the method identified by the symbol +method+, passing it any arguments
  # and/or the block specified, just like the regular Ruby <tt>Object#send</tt> does.
  #
  # *Unlike* that method however, a +NoMethodError+ exception will *not* be raised
  # and +nil+ will be returned instead, if the receiving object is a +nil+ object or NilClass.
  #
  # If try is called without a method to call, it will yield any given block with the object.
  #
  # ==== Examples
  #
  # Without try
  # @person && @person.name
  # or
  # @person ? @person.name : nil
  #
  # With try
  # @person.try(:name)
  #
  # +try+ also accepts arguments and/or a block, for the method it is trying
  # Person.try(:find, 1)
  # @people.try(:collect) {|p| p.name}
  #
  # Without a method argument try will yield to the block unless the reciever is nil.
  # @person.try { |p| "#{p.first_name} #{p.last_name}" }
  #--
  # +try+ behaves like +Object#send+, unless called on +NilClass+.
  def try(*a, &b)
    if a.empty? && block_given?
      yield self
    else
      __send__(*a, &b)
    end
  end
end

class NilClass #:nodoc:
  def try(*args)
    nil
  end
end

其实只是判断了 if a.empty? && block_given? 这种情况 则直接执行block 内容然后返回,效果一样…..

DEMO:

require "active_support/core_ext/object/try"

class Klass

  def send(*args)
    "helo " + args.join(' ')
  end

  def hello(*args)
    "Hello " + args.join(' ')
  end

  def self.foobar(s)
     "#{s} foobar"
  end
end

k = Klass.new

# __send__ 为了防止有方法名叫send , 建议用 __send__
p k.__send__ :hello, "gentle", "readers"   #=> "Hello gentle readers" 
p k.send "gentle", "readers"   #=> "Helo gentle readers"

# Ruby 里一切皆是对象,类也是对象
# Klass(类) 是 Class 的实例 , Class 是 Object 的实例 , 那么 Klass 也就是 Object 的实例 所以 Klass 可以调用try 方法
p Klass.try(:foobar,"hey") # => "hey foobar"
# k 是Klass 的实例,Klass 的父类是 Object , 所以 k 可以调用 try 方法
p k.try(:send,"bla","bla") # => "helo bla bla"

# class 得到的是 实例关系
# superclass 得到的是 继承关系
p Klass.superclass # Object
p Klass.class # Class
p k.class # Klass

另外 这是 对象nil 那如果 没有那个字段了 , 就会 报 找不到方法的错误

例如:

ruby-1.9.2-p0 > u=User.first
  User Load (175.8ms)  SELECT `users`.* FROM `users` LIMIT 1
 => #<User id: 1, login: "entos", name: "", email: "entos@entos.com", crypted_password: "557c88b0713f63397249f4198368e4a57d6d400f", salt: "4e04ef1cf506595ac3edf6a249791c55995b0f8f", remember_token: nil, remember_token_expires_at: nil, activation_code: nil, activated_at: nil, status: 2, suspend_at: nil, avatar_id: nil, orgunit_id: nil, mobile_phone: nil, last_login_at: nil, language: nil, options: nil, created_at: "2011-02-24 02:55:42", updated_at: "2011-02-24 02:55:42"> 
ruby-1.9.2-p0 > u.hi
NoMethodError: undefined method `hi' for #<User:0x9fcfe00>

建议加上 respond_to? 判断

ruby-1.9.2-p0 > u.respond_to? "hi"
 => false

This entry was posted on Thu, 13 Jan 2011 19:20:00 GMT and Posted in . You can follow any any response to this entry through the Atom feed. You can leave a comment or a trackback from your own site.

Tags , ,


Trackbacks

Use the following link to trackback from your own site:
http://wxianfeng.com/trackbacks?article_id=164

Comments

  1. Avatar
    sites inside almost {{count}} years ago:

    F*ckin’ awesome issues here. I am very glad to peer your article.
    Thankks a lot and i’m taking a look ahead to touch you.
    Will you please drop me a mail?

  2. Avatar
    Abijah almost {{count}} years ago:

    I just could not go away your siite before suggesting that I actually
    enjoyed the standard info an individual provide on your guests?
    Is going to be back frequently in order to inspect new posts

  3. Avatar
    Josette almost {{count}} years ago:

    Hi to every one, the contents present at this site are actually
    amazing for people experience, well, keep up the nice work fellows.

  4. Avatar
    Kit about {{count}} years ago:

    Admiring the time and energy you put into your
    website and in depth information you provide.
    It’s good to come across a blog every once in a while that isn’t the same outdated rehashed material.
    Wonderful read! I’ve bookmarked your site and I’m including your RSS feeds to my Google account.

  5. Avatar
    Kit about {{count}} years ago:

    Admiring the time and energy you put into your website and
    in depth information you provide. It’s good to
    come across a blog every once in a while that isn’t the same outdated rehashed material.
    Wonderful read! I’ve bookmarked your site and I’m including your RSS feeds to my Google
    account.

  6. Avatar
    apple about {{count}} years ago:

    Actually no matter if someone doesn’t understand then its up to other viewers that they
    will help, so here it happens.

  7. Avatar
    apple about {{count}} years ago:

    Actually no matter if someone doesn’t understand then its
    up to other viewers that they will help, so here it happens.

  8. Avatar
    te caldo about {{count}} years ago:

    I do not know if it’s just me or if perhaps everybody else encountering problems with
    your blog. It appears as if some of the
    written text on your content are running off the screen. Can somebody else please comment and let me know if this is happening
    to them as well? This could be a problem with my internet browser because I’ve had this happen before.

    Thank you

  9. Avatar
    te caldo about {{count}} years ago:

    I do not know if it’s just me or if perhaps everybody
    else encountering problems with your blog. It appears as
    if some of the written text on your content are running off the screen.
    Can somebody else please comment and let me know if this is
    happening to them as well? This could be a problem with my
    internet browser because I’ve had this happen before. Thank you

Leave a comment