• #3 楼 @cxh116 版本似乎还是不一样嘛 我代码是这样的

    # Active Record validation is reported to and from this object, which is used by Base#save to
    # determine whether the object is in a valid state to be saved. See usage example in Validations.
    class Errors
      include Enumerable
    
      class << self
        def default_error_messages
          ActiveSupport::Deprecation.warn("ActiveRecord::Errors.default_error_messages has been deprecated. Please use I18n.translate('activerecord.errors.messages').")
          I18n.translate 'activerecord.errors.messages'
        end
      end
    
      def initialize(base) # :nodoc:
        @base, @errors = base, {}
      end
    
      # Adds an error to the base object instead of any particular attribute. This is used
      # to report errors that don't tie to any specific attribute, but rather to the object
      # as a whole. These error messages don't get prepended with any field name when iterating
      # with +each_full+, so they should be complete sentences.
      def add_to_base(msg)
        add(:base, msg)
      end
    
      # Adds an error message (+messsage+) to the +attribute+, which will be returned on a call to <tt>on(attribute)</tt>
      # for the same attribute and ensure that this error object returns false when asked if <tt>empty?</tt>. More than one
      # error can be added to the same +attribute+ in which case an array will be returned on a call to <tt>on(attribute)</tt>.
      # If no +messsage+ is supplied, :invalid is assumed.
      # If +message+ is a Symbol, it will be translated, using the appropriate scope (see translate_error).
      def add(attribute, message = nil, options = {})
        message ||= :invalid
        message = generate_message(attribute, message, options) if message.is_a?(Symbol)
        @errors[attribute.to_s] ||= []
        @errors[attribute.to_s] << message
      end
    
      # Will add an error message to each of the attributes in +attributes+ that is empty.
      def add_on_empty(attributes, custom_message = nil)
        for attr in [attributes].flatten
          value = @base.respond_to?(attr.to_s) ? @base.send(attr.to_s) : @base[attr.to_s]
          is_empty = value.respond_to?(:empty?) ? value.empty? : false
          add(attr, :empty, :default => custom_message) unless !value.nil? && !is_empty
        end
      end
    
      # Will add an error message to each of the attributes in +attributes+ that is blank (using Object#blank?).
      def add_on_blank(attributes, custom_message = nil)
        for attr in [attributes].flatten
          value = @base.respond_to?(attr.to_s) ? @base.send(attr.to_s) : @base[attr.to_s]
          add(attr, :blank, :default => custom_message) if value.blank?
        end
      end
    
      # Translates an error message in it's default scope (<tt>activerecord.errrors.messages</tt>).
      # Error messages are first looked up in <tt>models.MODEL.attributes.ATTRIBUTE.MESSAGE</tt>, if it's not there, 
      # it's looked up in <tt>models.MODEL.MESSAGE</tt> and if that is not there it returns the translation of the 
      # default message (e.g. <tt>activerecord.errors.messages.MESSAGE</tt>). The translated model name, 
      # translated attribute name and the value are available for interpolation.
      #
      # When using inheritence in your models, it will check all the inherited models too, but only if the model itself
      # hasn't been found. Say you have <tt>class Admin < User; end</tt> and you wanted the translation for the <tt>:blank</tt>
      # error +message+ for the <tt>title</tt> +attribute+, it looks for these translations:
      # 
      # <ol>
      # <li><tt>activerecord.errors.models.admin.attributes.title.blank</tt></li>
      # <li><tt>activerecord.errors.models.admin.blank</tt></li>
      # <li><tt>activerecord.errors.models.user.attributes.title.blank</tt></li>
      # <li><tt>activerecord.errors.models.user.blank</tt></li>
      # <li><tt>activerecord.errors.messages.blank</tt></li>
      # <li>any default you provided through the +options+ hash (in the activerecord.errors scope)</li>
      # </ol>
      def generate_message(attribute, message = :invalid, options = {})
    
        message, options[:default] = options[:default], message if options[:default].is_a?(Symbol)
    
        defaults = @base.class.self_and_descendants_from_active_record.map do |klass|
          [ :"models.#{klass.name.underscore}.attributes.#{attribute}.#{message}", 
            :"models.#{klass.name.underscore}.#{message}" ]
        end
    
        defaults << options.delete(:default)
        defaults = defaults.compact.flatten << :"messages.#{message}"
    
        key = defaults.shift
        value = @base.respond_to?(attribute) ? @base.send(attribute) : nil
    
        options = { :default => defaults,
          :model => @base.class.human_name,
          :attribute => @base.class.human_attribute_name(attribute.to_s),
          :value => value,
          :scope => [:activerecord, :errors]
        }.merge(options)
    
        I18n.translate(key, options)
      end
    
      # Returns true if the specified +attribute+ has errors associated with it.
      #
      #   class Company < ActiveRecord::Base
      #     validates_presence_of :name, :address, :email
      #     validates_length_of :name, :in => 5..30
      #   end
      #
      #   company = Company.create(:address => '123 First St.')
      #   company.errors.invalid?(:name)      # => true
      #   company.errors.invalid?(:address)   # => false
      def invalid?(attribute)
        !@errors[attribute.to_s].nil?
      end
    
      # Returns +nil+, if no errors are associated with the specified +attribute+.
      # Returns the error message, if one error is associated with the specified +attribute+.
      # Returns an array of error messages, if more than one error is associated with the specified +attribute+.
      #
      #   class Company < ActiveRecord::Base
      #     validates_presence_of :name, :address, :email
      #     validates_length_of :name, :in => 5..30
      #   end
      #
      #   company = Company.create(:address => '123 First St.')
      #   company.errors.on(:name)      # => ["is too short (minimum is 5 characters)", "can't be blank"]
      #   company.errors.on(:email)     # => "can't be blank"
      #   company.errors.on(:address)   # => nil
      def on(attribute)
        errors = @errors[attribute.to_s]
        return nil if errors.nil?
        errors.size == 1 ? errors.first : errors
      end
    
      alias :[] :on
    
      # Returns errors assigned to the base object through +add_to_base+ according to the normal rules of <tt>on(attribute)</tt>.
      def on_base
        on(:base)
      end
    
      # Yields each attribute and associated message per error added.
      #
      #   class Company < ActiveRecord::Base
      #     validates_presence_of :name, :address, :email
      #     validates_length_of :name, :in => 5..30
      #   end
      #
      #   company = Company.create(:address => '123 First St.')
      #   company.errors.each{|attr,msg| puts "#{attr} - #{msg}" }
      #   # => name - is too short (minimum is 5 characters)
      #   #    name - can't be blank
      #   #    address - can't be blank
      def each
        @errors.each_key { |attr| @errors[attr].each { |msg| yield attr, msg } }
      end
    
      # Yields each full error message added. So <tt>Person.errors.add("first_name", "can't be empty")</tt> will be returned
      # through iteration as "First name can't be empty".
      #
      #   class Company < ActiveRecord::Base
      #     validates_presence_of :name, :address, :email
      #     validates_length_of :name, :in => 5..30
      #   end
      #
      #   company = Company.create(:address => '123 First St.')
      #   company.errors.each_full{|msg| puts msg }
      #   # => Name is too short (minimum is 5 characters)
      #   #    Name can't be blank
      #   #    Address can't be blank
      def each_full
        full_messages.each { |msg| yield msg }
      end
    
      # Returns all the full error messages in an array.
      #
      #   class Company < ActiveRecord::Base
      #     validates_presence_of :name, :address, :email
      #     validates_length_of :name, :in => 5..30
      #   end
      #
      #   company = Company.create(:address => '123 First St.')
      #   company.errors.full_messages # =>
      #     ["Name is too short (minimum is 5 characters)", "Name can't be blank", "Address can't be blank"]
      def full_messages(options = {})
        full_messages = []
    
        @errors.each_key do |attr|
          @errors[attr].each do |message|
            next unless message
    
            if attr == "base"
              full_messages << message
            else
              attr_name = @base.class.human_attribute_name(attr)
              full_messages << attr_name + I18n.t('activerecord.errors.format.separator', :default => ' ') + message
            end
          end
        end
        full_messages
      end 
    
      # Returns true if no errors have been added.
      def empty?
        @errors.empty?
      end
    
      # Removes all errors that have been added.
      def clear
        @errors = {}
      end
    
      # Returns the total number of errors added. Two errors added to the same attribute will be counted as such.
      def size
        @errors.values.inject(0) { |error_count, attribute| error_count + attribute.size }
      end
    
      alias_method :count, :size
      alias_method :length, :size
    
      # Returns an XML representation of this error object.
      #
      #   class Company < ActiveRecord::Base
      #     validates_presence_of :name, :address, :email
      #     validates_length_of :name, :in => 5..30
      #   end
      #
      #   company = Company.create(:address => '123 First St.')
      #   company.errors.to_xml
      #   # =>  <?xml version="1.0" encoding="UTF-8"?>
      #   #     <errors>
      #   #       <error>Name is too short (minimum is 5 characters)</error>
      #   #       <error>Name can't be blank</error>
      #   #       <error>Address can't be blank</error>
      #   #     </errors>
      def to_xml(options={})
        options[:root] ||= "errors"
        options[:indent] ||= 2
        options[:builder] ||= Builder::XmlMarkup.new(:indent => options[:indent])
    
        options[:builder].instruct! unless options.delete(:skip_instruct)
        options[:builder].errors do |e|
          full_messages.each { |msg| e.error(msg) }
        end
      end
    
    end
    

    现在只能用 class_eval 控制@errors变量了,感觉代码超级丑陋

  • #1 楼 @cxh116 你的 Rails 版本太新了,我这里是 2.3 的。API 差不多就是这样:http://ar.rubyonrails.org/classes/ActiveRecord/Errors.html 没有 delete 方法。

  • Shell 是啥?

  • Prolog 是啥?

  • ruby 有什么热点的 QQ 群吗? at 2012年11月09日

    写 Ruby 的人和用 QQ 的人的文化是冲突的吧 你还是用邮件吧

  • 关于符号~> at 2012年11月08日

    约等于啊

  • 求推荐能记账的好网站 at 2012年11月06日

    在想如何证明这些网站能保护我们的隐私

  • macvim 下 rvm 不管用 at 2012年11月06日

    Good.

  • #2 楼 @sunmoonstr 额 HAProxy 是用来实现分布式的 web server,与 session 无关,session 共享还是需要使用 memcached 或是数据库来实现的。

    1. try HAProxy
    2. 使用 memcached 或者数据库存储 session(cookie 也可以,但是容量有限制),sinatra 不了解,Rails 可以很容易的实现这个方法。
  • Ruby 2.0 新功能演示 at 2012年11月04日

    当初做一个模拟用户不定期发送 http 请求的模拟器的时候,就有意使用了 fork 做多进程,就是为了防止不能并发 http 请求。

  • Ruby 2.0 新功能演示 at 2012年11月04日
    # double splat to capture all keyword arguments, or use as hash as keyword, 两个星号表示可以把整个keyword arguments抓下来
    # arguments
    def capture(**opts)
      opts
    end
    p capture(foo: "bar")                          #=> {:foo=>"bar"} 返回的是hash
    
    # keys must be symbols 传进的key一定要是hash 
    opts = {:before => "(", :after => ")"}
    p wrap("foo", **opts)         #=> "(foo)"  注意这里的**opts, 代表把上面的opts当做keyword arguments
    
    #旧的hash传参数方法继续支持,其实用起来不会有太大的不同
    p wrap("foo", :before => "{", :after => "}")   #=> "{foo}"
    

    其实没怎么看懂,def capture(**opts) 和 def capture(opts) 的区别是什么?都可以直接接受一个 hash 啊

  • @nash_su 不能访问

  • 光盘安装

  • 播客的视频有订阅功能吗?或是有没有个专门的 twitter 帐号负责订阅的?

  • #26 楼 @nash_su 挖 到底是创业公司,速度好快。。我们这种大公司的情何以堪啊

  • #24 楼 @nash_su 支持它又没什么成本,如果有就直接用,如果没有也支持自己上传

  • 建议支持 Gravatar,我真的找不到我的常用头像的原文件了。。

  • #19 楼 @nash_su 挖 好快!

    1. 观看播客,发表评论
    2. 提示没有登录,随即输入用户名密码登录
    3. 回到刚才页面

    expected: 评论依然出现在文本框中 或者 评论已经发出 actual: 评论丢失

  • @nash_su 播客看上去不错 希望能经常更新

  • @nash_su 是“登录”不是“登陆”

  • @nash_su 总体上还是红帽认证相关的课程,可惜我早就过了,不知道能不能有一些与 Linux 开发相关的课程呢?

  • #10 楼 @zz 我倒是不能忍受不用写 end 的 python

  • 不过说真的,我现在对于 Ruby without Rails 的兴趣已经远远大于 Rails 了。

  • 我能说我用 Ruby 做过一个图形界面的小程序吗,不过由于用的图形库非常不成熟,界面超级丑陋。但无论如何,这个图形库的 API 风格给我留下了非常深刻的印象,与传统的 C++,Java 图形库相比确实很不一样。

  • #2 楼 @adventurelw Rails 的单复数可不是简单的+s,而是真的有张列表去管理的。

  • 现在很多游戏 XP 上都不能运行了,不装 Win7 怎么行

  • Gem 依赖冲突的问题 at 2012年10月29日

    我在想这里一定要用 multi_json 吗?如果换成普通的 json 解析方法不行吗?