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
    greece ferry almost {{count}} years ago:

    Tremendous issues here. I’m very glad to look your article.
    Thanks so much and I’m taking a look ahead to toucch you.
    Will you please drop me a e-mail?

  2. Avatar
    greece ferry almost {{count}} years ago:

    Tremendous issues here. I’m very glad to look your article.
    Thanks so muhch and I’m taking a look ahead too touch you.

    Will you please drop me a e-mail?

  3. Avatar
    greece ferry almost {{count}} years ago:

    No matter if some one searches for his required thing, thherefore
    he/she wishes tto be available that in detail,so thast hing is maintained over here.

  4. Avatar
    indcreateforum.url.ph almost {{count}} years ago:

    I am really loving tthe theme/design of your site.
    Do you ever ruun into any internet browser compatibility problems?

    A few of my blog visitors have complained about my website noot working correctly in Explorer but
    looks great in Safari. Do you have any solutions to help fix
    this issue?

  5. Avatar
    Archie almost {{count}} years ago:

    Hi there, I enjoy reading thnrough your article post.
    I wanted to write a litftle comment too support you.

Leave a comment