【问题标题】:Defining a Rails helper (or non-helper) function for use everywhere, including models定义一个在任何地方都可以使用的 Rails 辅助(或非辅助)函数,包括模型
【发布时间】:2012-08-07 19:37:31
【问题描述】:

我有一个功能可以做到这一点:

  def blank_to_negative(value)
    value.is_number? ? value : -1
  end

如果传递的值不是数字,则将值转换为-1。

我主要为某个模型创建了这个函数,但是在任何某个模型中定义这个函数似乎并不合适,因为这个函数的应用范围显然可以扩展到任何一个特定的模型之外。我几乎肯定会在其他模型中需要此功能,并且可能在视图中。

什么是最“Rails Way”的方式来定义这个函数,然后在任何地方使用它,尤其是在模型中?

我尝试在ApplicationHelper中定义它,但没有成功:

class UserSkill < ActiveRecord::Base
  include ApplicationHelper
  belongs_to :user
  belongs_to :skill

  def self.splice_levels(current_proficiency_levels, interest_levels)
    Skill.all.reject { |skill| !current_proficiency_levels[skill.id.to_s].is_number? and !interest_levels[skill.id.to_s].is_number? }.collect { |skill| {
      :skill_id => skill.id,
      :current_proficiency_level => blank_to_negative(current_proficiency_levels[skill.id.to_s]),
      :interest_level => blank_to_negative(interest_levels[skill.id.to_s]) }}
  end 
end

这告诉我

用于#的未定义方法`blank_to_negative'

无论如何,我已经读过you're "never" supposed to do that kind of thing,所以我有点困惑。

【问题讨论】:

  • 如果你需要在很多地方使用这个逻辑,我感觉你的设计存在缺陷。
  • 好点。你可能是对的。根本原因是我的应用程序中的某些内容可以被用户评为 0-10。如果用户不输入评分,则用户的评分不是未知的,它只是已知为空白,因此我想存储一个 NULL(表示“未知”),而不是存储一个不同的值,我选择了-1。欢迎提出关于更好解决方案的建议(尽管肯定与原始问题无关)。
  • 好消息是 nil 和空白字符串在与 to_i 一起使用时默认为 0
  • 但 0 是合法评级,空白或无效值不应默认为合法评级 0。
  • 我会使用 null 来表示空白值。这就是它的用途。无论是因为未知而为空白,还是因为不存在而为空白,还是因为故意为空白而为空白,都只是空白。 Nil/null 是 blank 值的正确概念。

标签: ruby-on-rails


【解决方案1】:

如果您想在项目中的 每个 类中使用这样的辅助方法,那么您可以随意将其作为方法添加到 Object 或任何您认为合适的方法:

module MyApp
  module CoreExtensions
    module Object
      def blank_to_negative
        self.is_number? ? self : -1
      end
    end
  end
end

Object.send :include, MyApp::CoreExtensions::Object

【讨论】:

  • 好的,我认为这是有道理的。如果我只在字符串上使用它,我猜我会使用module String 而不是module Object?我会将这段代码放在什么文件中?
  • 没错!我通常会在我的应用程序中添加一个extensions 目录并将类似的东西放在那里。其他人将它们放入 lib/core_ext 我不知道 Rails 应用程序的最佳实践。
  • 嗯,我把它放在app/extensions/string.rb 中,但它不起作用(未定义的方法),即使我重新启动了我的服务器。
  • 我建议使用 Rails 初始化程序来调用 Object.send 部分
  • @JasonSwett 把它放在config/initalizers/core_extensions.rb 中,当它变得太拥挤时改进
【解决方案2】:

有几个选项:

  • Monkey 将该方法修补到 ActiveRecord 中,它将在您的所有模型中可用:

    class ActiveRecord::Base
      def blank_to_negative(value)
        value.is_number? ? value : -1
      end
    end
    
  • 添加一个“关注”模块,然后将其混合到选定的模型中:

    # app/concerns/blank_to_negate.rb
    module BlankToNegate
      def blank_to_negative(value)
        value.is_number? ? value : -1
      end
    end
    
    # app/models/user_skill.rb
    class UserSkill < ActiveRecord::Base
      include BlankToNegate
      # ...
    end
    

【讨论】:

  • 如果我同意你的第一个想法,我会用self.blank_to_negative(value)blank_to_negative(value) 来称呼它吗?如果是前者,我觉得那完全没有道理。
【解决方案3】:

Ruby 数据类型功能可以扩展。它们没有密封。既然你想在所有地方使用它,为什么不扩展 FIXNUM 功能并添加一个方法 blank_to_negative 到它。

【讨论】:

  • are close to modification => wat?!
【解决方案4】:

这就是我最终要做的。我把这段代码放在config/initializers/string_extensions.rb.

class String
  def is_number?
    true if Float(self) rescue false
  end 

  def negative_if_not_numeric
    self.is_number? ? self : -1
  end 
end

另外,我将blank_to_negative 重命名为negative_if_not_numeric,因为some_string.negative_if_not_numericsome_string.blank_to_negative 更有意义。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2011-07-28
    • 2023-03-03
    • 2022-01-08
    • 2016-11-25
    • 2019-08-02
    • 2011-03-27
    • 2018-12-13
    • 1970-01-01
    相关资源
    最近更新 更多