• 实际上,if: :password_required?if option 特性,并不是来做ActiveModel 而是来自 ActiveSupport::Callbacks。之前好像有一个帖子专门讨论callback的。

    我把整个定义这个 validate 过程写下来,以Rails 5代码为例,你就能看到在哪里执行 if 了。

    首先是 validates的定义 code

    注意这段代码,validates_with(validator, defaults.merge(_parse_validates_options(options)))

    validates_with的定义在这里 code

    然后有看到了,validate(validator, options)

    validate 的定义在这里 code

    首先看到这里,好激动,看到了if

    if options.key?(:on)
      options = options.dup
      options[:if] = Array(options[:if])
      options[:if].unshift ->(o) {
        !(Array(options[:on]) & Array(o.validation_context)).empty?
      }
    end
    

    同时下面还有一段 set_callback(:validate, *args, &block) 我们的if还在 args 里面

    到这里大概明白,实际上 validate 就是一个 callback

    那么set_callback是什么鬼?

    网上找会看到这段代码

    included do
        extend ActiveModel::Naming
        extend ActiveModel::Callbacks #这个!!这个!!
        extend ActiveModel::Translation
    
    

    然后找到了ActiveModel::Callback定义的地方。code,但是,实际上这里并没有做什么。

    然后又看到了,

    def self.extended(base) #:nodoc:
      base.class_eval do
        include ActiveSupport::Callbacks
      end
    end
    

    终于到了ActiveSupport::Callbacks ,我们找到的是set_callback的定义

    定义在这里code

    其中有这段代码

    mapped = filters.map do |filter|
        Callback.build(self_chain, filter, type, options)
    end
    

    然后要找的就是Callback的定义了

    Callback code

    又一次兴奋的看到了if

    def initialize(name, filter, kind, options, chain_config)
      @chain_config  = chain_config
        @name    = name
      @kind    = kind
    @filter  = filter
        @key     = compute_identifier filter
      @if      = Array(options[:if]) # 这个!!这个!!
      @unless  = Array(options[:unless])
    end
    

    接下来的问题,其实就比较轻松了,这和Callback被执行时的,@if 是如何处理的。

    在当前的页面,还能看到这段代码

    def conditions_lambdas
        @if.map { |c| CallTemplate.build(c, self).make_lambda } +
          @unless.map { |c| CallTemplate.build(c, self).inverted_lambda }
    end
    

    这里,整个 @if Array 转化成了一个由 CallTemplate.build(c, self).make_lambda 组成的Array,里面是什么呢?是lambda

    接着就是要搞这个 conditions_lambdas返回的 Array 去了哪里。

    我们还是在同一个文件里code

    def apply(callback_sequence)
      user_conditions = conditions_lambdas
      user_callback = CallTemplate.build(@filter, self)
    
      case kind
      when :before
        Filters::Before.build(callback_sequence, user_callback.make_lambda, user_conditions, chain_config, @filter)
      when :after
        Filters::After.build(callback_sequence, user_callback.make_lambda, user_conditions, chain_config)
      when :around
        callback_sequence.around(user_callback, user_conditions)
      end
    end
    

    这里其实有涉及到了,ActiveSupport::Callbacks的执行逻辑,就不再深入,直接跳到最终执行的地方,还是同一个文件code

    def skip?(arg)
      arg.halted || !@user_conditions.all? { |c| c.call(arg.target, arg.value) }
    end
    

    这里有!@user_conditions.all? { |c| c.call(arg.target, arg.value) } 因为这是一个 Array

    查看 Enumerable .all?的定义。code

    all? [{ |obj| block } ] → true or false
    Passes each element of the collection to the given block. The method returns true if the block never returns false or nil. If the block is not given, Ruby adds an implicit block of { |obj| obj } which will cause all? to return true when none of the collection members are false or nil.
    

    所以,if options 实际上是在这里执行的。

  • #4 楼 @miserytan @first_dow@last_dow 是为了存放你的结果,避免重复计算。 when 1 怎么不理解? 这个算法其实你可以自己去实现的。

  • 补充一下,为什么要用上面的算法,是为了过滤你在 Settings.start_of_week中设置 1-7 以外的数字。你也可以用别的算法。

  • 关于 Ruby 的线上视频培训 at 2016年10月10日

    支持

    1. 代码格式有点问题,多复制了一个 end 你理解的是对的 first_wday 返回的是一周的第一天是哪一天 last_wday 返回的是一周的最后一天是哪一天

    2. 为什么开始都是星期日? 因为这段代码 Setting.start_of_week.to_i 返回的是 7,也就是默认设置的就是星期日是第一天, 如果你希望是星期一是第一天,那么 Settings.start_of_week 应该改成 1

  • select_tagf.select 是不同的。 你看一下这两个函数参数的区别。

    1. select_tag
    2. f.select

    你这里其实有两个问题,

    1. form 中的内容 province/city/area 没有提交并被保存,所以 show 中看不到。
    2. china_city 在使用f.select时不工作但是能够提交。

    我给几个提示

    1. 你看一下 f.selectselect_tag生成的 HTML 代码有什么不同,它们具体是怎么用的。
    2. 再看一下 china_city 中 demo 中的 html 是什么样子的。
    3. province 被保存和没有被保存的两种情况下,HTML 代码有什么区别?
  • #4 楼 @xiaobai2 是你的判断逻辑有问题。 你想要在一个小时内只能插入 1 条,但是你判断的是 count > 1,当你插入第二条时,此时 count 是 1 啊,并不满足你的条件。你应该判断 count == 1

  • #7 楼 @Mineor 你是怎么发起请求的?

  • #2 楼 @zix 如 4 楼所说,你没明白你要做的是什么,你先你问的问题有点像是,1 + 1 = 2 了,但是你希望这个结果是 3,能不能想办法让 1 + 1 = 3,哪怕可以。但是你改变了基础的东西。😀 我的建议是,你回头想想你要实现什么?然后再想想,用什么来实现,一定要页面跳转吗?不同用一个 Post 请求来实现?

  • 刷新页面不就是重新请求吗?!当然会执行 action 啊。

  • 哈哈哈,两斤花椒吃了 3 年😏

  • #5 楼 @xiaobai2 都可能是。

  • 你用错了find_by 看链接

  • #4 楼 @lehug 贴一下具体的代码吧 在用一下他贴的@u1440247613 网站,http://js2.coffee/ 看翻译出来的 JavaScript 是不是正确的。

  • 首先,(this)不是普通 JS 的用法,是带 jQuery 库的 JS。 所以如果你引入了 jQuery 库,在 CoffeeScript 中依然可以这么用$(this),没有问题,如果不行就要查一下其他原因了。 如果是纯 JavaScript,参见Element.getAttribute(attrName)

  • 不会写前端感觉太痛苦了 at 2016年06月18日

    要是不喜欢 bootstrap,可以看看 semantic ui,或者直接 muicss。给我女朋友用的话,只要不难看就好了吧,有功能就很好了。

  • 我懂你的意思了,我理解错了#5 楼 @geekjj

  • 对 Redis 没有深入了解过,以前做一个文章阅读应用,我们把文章的内容放到了 Redis 里。所以可以理解为,会被经常访问到,但又不经常变化,每次查数据库开销又比较大的数据可以放到 Redis 中。Redis 应该还有其他很多用法,下面肯定还会有人补充。

  • 那为什么不在 Model 里直接加一个 validate?

  • 目前在 Rails 4.2.4 中我使用的方法,以防有人看到

    # 在Rails初始化时加入
    ActiveSupport::NumberHelper::NumberToHumanConverter::DECIMAL_UNITS[4] = :wan # 万
    ActiveSupport::NumberHelper::NumberToHumanConverter::DECIMAL_UNITS[8] = :yi  # 亿
    ActiveSupport::NumberHelper::NumberToHumanConverter::INVERTED_DECIMAL_UNITS = ActiveSupport::NumberHelper::NumberToHumanConverter::DECIMAL_UNITS.invert
    

    在 config/locales/zh.yml 文件中加入翻译

    zh:
      number:
        human:
          decimal_units:
            units:
              unit: ""
              thousand: "千"
              wan: "万"
              million: "百万"
              yi: "亿"
              billion: "十亿"
              trillion: "万亿"
              quadrillion: "千万亿"
    

    然后调用

    number_to_human(10000, locale: :zh)
    
    # "1 万"
    
    number_to_human(100000000, locale: :zh)
    
    # 1 亿
    
  • 谢谢,赞

  • #1 楼 @lgn21st 谢谢

  • #9 楼 @gene_wu 了解,谢谢

  • #5 楼 @rei 😄 好的,谢谢,主要就是想确认是否不兼容,如果真的不兼容。就直接清 Cache。

  • #6 楼 @hooooopo 不奇怪,主要时因为看到了下面这个方法,以为是可以兼容的,但没有找到使用方式。感谢回复 😄

    # The internals of this method changed between Rails 3.x and 4.0. This method provides the glue
    # to ensure that cache entries created under the old version still work with the new class definition.
    def convert_version_4beta1_entry!
      if defined?(@v)
        @value = @v
        remove_instance_variable(:@v)
      end
      if defined?(@c)
        @compressed = @c
        remove_instance_variable(:@c)
      end
      if defined?(@x) && @x
        @created_at ||= Time.now.to_f
        @expires_in = @x - @created_at
        remove_instance_variable(:@x)
      end
    end
    
  • #3 楼 @hooooopo #2 楼 @gene_wu 是的,清除 Cache 以后一切正常。 那是不是每次部署之前,最好都清除 Cache?这么做的原因是?

  • 👏