实际上,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 以外的数字。你也可以用别的算法。
支持
代码格式有点问题,多复制了一个 end 你理解的是对的 first_wday 返回的是一周的第一天是哪一天 last_wday 返回的是一周的最后一天是哪一天
为什么开始都是星期日?
因为这段代码 Setting.start_of_week.to_i
返回的是 7,也就是默认设置的就是星期日是第一天,
如果你希望是星期一是第一天,那么 Settings.start_of_week
应该改成 1
select_tag
和 f.select
是不同的。
你看一下这两个函数参数的区别。
你这里其实有两个问题,
f.select
时不工作但是能够提交。我给几个提示
f.select
和 select_tag
生成的 HTML 代码有什么不同,它们具体是怎么用的。刷新页面不就是重新请求吗?!当然会执行 action 啊。
哈哈哈,两斤花椒吃了 3 年
你用错了find_by
看链接
#4 楼 @lehug 贴一下具体的代码吧 在用一下他贴的@u1440247613 网站,http://js2.coffee/ 看翻译出来的 JavaScript 是不是正确的。
首先,(this)
不是普通 JS 的用法,是带 jQuery 库的 JS。
所以如果你引入了 jQuery 库,在 CoffeeScript 中依然可以这么用$(this)
,没有问题,如果不行就要查一下其他原因了。
如果是纯 JavaScript,参见Element.getAttribute(attrName)
要是不喜欢 bootstrap,可以看看 semantic ui,或者直接 muicss。给我女朋友用的话,只要不难看就好了吧,有功能就很好了。
对 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 亿
谢谢,赞
#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