Ruby 重构代码,包括;“双管”;及;实例变量";使用元编程
我有两种方法:Ruby 重构代码,包括;“双管”;及;实例变量";使用元编程,ruby,metaprogramming,Ruby,Metaprogramming,我有两种方法: def ios_ids @ios_ids ||= Array(GcmToken.find_by(users_id: "#{@event.user_id}", os_type: 'ios', alive: true).try(:reg_id)) end def android_ids @android_ids ||= Array(GcmToken.find_by(users_id: "#{@event.user_id}", os_type: 'android
def ios_ids
@ios_ids ||= Array(GcmToken.find_by(users_id: "#{@event.user_id}", os_type: 'ios', alive: true).try(:reg_id))
end
def android_ids
@android_ids ||= Array(GcmToken.find_by(users_id: "#{@event.user_id}", os_type: 'android', alive: true).try(:reg_id))
end
我想把它们折射成下面这样的东西
%w(android ios).each do |os_type|
define_method(:"#{os_type}_ids") { "@#{os_type}_ids" ||= Array(GcmToken.find_by(users_id: "#{@event.user_id}", os_type: os_type, alive: true).try(:reg_id))}
end
但它不起作用
有人有任何答案或更好的解决方案吗?您想使用,并且:
使用这种元编程真的很麻烦,尤其是在这样操作实例变量时。通常情况下,当你沿着这条路走的时候,这是因为你有很多类似的情况需要清理 让我们用更小的步骤来解决这个问题:
def ios_ids
@ios_ids ||= Array(GcmToken.find_by(users_id: "#{@event.user_id}", os_type: 'ios', alive: true).try(:reg_id))
end
这里发生了一些非常奇怪的事情,比如“#{x}”
反模式,它引用了一个几乎总是毫无意义的值。在绝对需要字符串的情况下,使用.to\u s
处理所讨论的值
这还会加载模型并尝试从中获取属性。那太浪费了。它还使用很少使用的不规则数组(…)
符号将其打包<代码>[…]是首选
所以你可以稍微整理一下:
def ios_ids
@ios_ids ||= GcmToken.where(
users_id: @event.user_id,
os_type: 'ios',
alive: true
).pluck(:reg_id)
end
这就归结了很多。现在它只是从GcmToken
模型中获取所有相关的reg\u id
值。如果您有一个用户拥有多个:gcm\u令牌
并且事件属于:User
,这里给出的数据应该是这种情况,那么您可以进一步清理它:
def ios_ids
@ios_ids ||= @event.user.gcm_tokens.where(
os_type: 'ios',
alive: true
).pluck(:reg_id)
end
您可以通过一个简单的scope
声明来进一步清理这个问题:
scope :alive_for_os_type, -> (os_type) {
where(os_type: os_type, alive: true)
}
然后它变得更小:
def ios_ids
@ios_ids ||= @event.user.gcm_tokens.alive_for_os_type('ios').pluck(:reg_id)
end
它变得越来越小了。在这一点上,使用define_method
减少这一点是过分的,但如果您真的想这样做,请执行以下操作:
OS_TYPES = %w[ android ios ].freeze
OS_TYPES.each do |os_type|
method_name = "#{os_type}_ids".to_sym
instance_var = "@#{method_name}".to_sym
define_method(method_name) do
instance_variable_get(instance_var) or
instance_variable_set(
instance_var,
@event.user.gcm_tokens.where(
os_type: 'ios',
alive: true
).pluck(:reg_id)
)
end
end
这比将每一个的实现简化为更简单的形式要糟糕得多,代码也要复杂得多。如果你有几十种类型,也许你会想这样做,但老实说,这个呢:
def platform_ids(os_type)
@platform_ids ||= { }
@platform_ids[os_type] ||= @event.user.gcm_tokens.alive_for_os_type(os_type).pluck(:reg_id)
end
有一种方法可以处理N种类型,您所要做的就是指定哪一种。有时特殊用途的方法不值得大惊小怪。@Ilya typo,你当然是对的,谢谢你的关注!我应该删除我的答案吗?@Ilya在这种情况下(当你看到有人在他的答案中犯了一个小错误/风格错误时),你可能应该编辑已经给出的答案,而不是提供一个新的答案,只提供更好的代码表示。这是国际海事组织,我并不声称这是一条规则或任何东西,只是我对常识的看法:)看起来很相似,我同意,但方式完全不同。@Andrey Deineko你给出了正确的答案,谢谢你的帮助你给出了正确的答案,还有很多建议,谢谢你的帮助。我会认真研究你的建议。嗨,我读过一篇文章,说我们应该使用interpolate而不是to__s,你能解决我的困惑吗?我应该使用什么样的情况来使用to_s或interpolate?这篇文章是@tsao,用于在模式为
“…{x}…”的字符串中进行插值,但是隔离变量是没有意义的。例如,do放置“Hello{name}”
,而不do放置“{name}”
。
def platform_ids(os_type)
@platform_ids ||= { }
@platform_ids[os_type] ||= @event.user.gcm_tokens.alive_for_os_type(os_type).pluck(:reg_id)
end