【问题标题】:Capitalizing more than one attribute in a Rails before_save method在 Rails before_save 方法中将多个属性大写
【发布时间】:2014-12-02 09:08:17
【问题描述】:

我想使用before_save 方法将我的模型实例的first_namelast_name 大写。我当然可以这样做:

before_save do 
  self.first_name = first_name.capitalize
  self.last_name = last_name.capitalize
end

但我更愿意一举改变这两个属性。有没有办法在我的模型中选择某些列并将所需的方法应用于它们?

【问题讨论】:

  • 这实际上是在将数据转换为 SQL 查询之前对其进行修改。这仍然只包含在一个 INSERT/UPDATE 语句中
  • 不确定downcase 是否将字符串字符大写。你确定你要做什么?
  • @Surya 很抱歉。修改代码以反映问题
  • @MrYoshiji 正确。与其说是“查询”数据库,不如说是缺少更好的术语,选择模型的所需列并应用 capitalize 方法。
  • 但最终你必须写出那些列名,对吧?为什么你认为这不是你想要的方式?

标签: ruby-on-rails ruby callback rails-activerecord models


【解决方案1】:

你可以这样做

before_save :capitalize_attributes

private
   def capitalize_attributes
     capitalizable = ["first_name","last_name"]
     self.attributes.each do |attr,val|
       #based on comment either of these will work
       #if you want to store nil in the DB then
       self.send("#{attr}=",val.strip.capitalize) if capitalizable.include?(attr) && !val.nil?
       #if you want to store a blank string in the DB then 
        self.send("#{attr}=",val.to_s.strip.capitalize) if capitalizable.include?(attr)
     end
   end

然后您可以将想要大写的属性添加到capitalizable 数组中。我在某些模型中使用与upcase all Strings 类似的代码,只是为了保持数据干净一致。

【讨论】:

  • 有了这个我得到:NoMethodError: undefined method 'strip' for nil:NilClass
  • @CarlEdwards 好的,所以您提交 nil 作为值,这很好,您可以修复查看更新的帖子。如果你想要我喜欢它,你可以放弃#strip,因为我不希望用户提交像“John”这样的名字。在这种情况下,#strip 将删除前导和尾随空格。
  • 谢谢!尽管浏览了 Ruby 文档,但我仍然有点不清楚 send 完成了什么。介意解释一下它在这种情况下的作用吗?
  • @CarlEdwards 简单来说#send 允许您在对象上调用方法而无需专门写出方法,因此这实际上是调用first_name= val.strip.capitalizelast_name= val.strip.capitalize。这实际上是每个方法的调用方式,尽管有些方法使用public_send,具体取决于调用它的范围。对于不适合评论的更深入的解释,只需谷歌发送在 ruby​​ 中的作用。
  • 非常感谢您的帮助
【解决方案2】:

在@engineersmnky 的Concerns(更多here)对Rails 4+ 的回答的基础上进一步构建:

app/models/concerns/model_hooks.rb

module ModelHooks
  extend ActiveSupport::Concern

  included do
    before_save :capitalize_attributes
  end

  def capitalize_attributes
     self.attributes.each do |attr,val|
       # if the attribute only has spaces, then this will store nil in the DB
       self.send("#{attr}=",val.strip.capitalize) if self.capitalizable_attrs.include?(attr) && !val.nil?
     end    
  end
end

然后在你的模型中:

class Trail < ApplicationRecord
  include ModelHooks

  def capitalizable_attrs
    ["name"] # return an array of attributes you want to capitalize
  end

end

【讨论】:

    【解决方案3】:

    这只是@engieeringmnky 答案的另一个版本:

    before_save :capitalize_attributes
    
    private
       def capitalize_attributes
         self.attributes.select{ |a| ["first_name","last_name"].include? a }.each do |attr, val|
           self.send("#{attr}=", val.try(:strip).try(:capitalize))
         end
       end
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2014-07-05
      • 1970-01-01
      • 1970-01-01
      • 2017-07-26
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-03-04
      相关资源
      最近更新 更多