FriendlyId在模型验证之前触发。我该如何解决这个问题?

时间:2012-06-22 03:07:36

标签: ruby-on-rails ruby ruby-on-rails-3 validation friendly-id

理想情况下,我希望网址看起来像:

/ users / john-s

/ users / foo-b

/用户/布拉德-P

我有一个如下所示的用户模型:

class User < ActiveRecord::Base
  extend FriendlyId
  friendly_id :name, :use => :slugged

  validates :first_name, :presence => true
  validates :last_name, :presence => true

  # "John Smith" becomes "John S."
  def name
    "#{self.first_name.capitalize} #{self.last_name[0].capitalize}."
  end
end

使用此控制台输出可以最好地解释不良行为:

[15] pry(main)> User.new(first_name: nil, last_name: nil).save!
   (0.2ms)  BEGIN
   (0.1ms)  ROLLBACK
NoMethodError: undefined method `capitalize' for nil:NilClass

问题(最后!:))

出现的情况是,在first_namelast_name的验证被触发之前,才会调用FriendlyId。这会导致name方法在使用nil值调用capitalize时进行pooping。

我可以做什么才能在调用FriendlyId之前触发我的验证?并且实际上更进一步......为什么在建立任何有效性之前,FriendlyId都参与其中?

谢谢!

3 个答案:

答案 0 :(得分:1)

调用它是因为在保存验证之前生成了slug:

https://github.com/FriendlyId/friendly_id/issues/280

我不太确定它是什么需要monkeypatch它。

答案 1 :(得分:1)

我修理我的方式是这样的:

  def name
    "#{self.first_name.capitalize} #{self.last_name[0].capitalize}." if first_name.present? && last_name[0].present?
  end

答案 2 :(得分:1)

我认为要采用的方法是在创建的before_validation中设置用户名,该用户名已预先设置在friendly_id自己的设置slug的before_validation回调之前:

class User < ActiveRecord::Base
  extend FriendlyId
  friendly_id :name, :use => :slugged

  # Make sure to prepend it so that it runs before Friendly_id's own callback
  # http://api.rubyonrails.org/classes/ActiveRecord/Callbacks.html
  before_validation :set_name, on: :create, prepend: true

  validates :first_name, :presence => true
  validates :last_name, :presence => true

  # To control when new slugs should be generated
  def should_generate_new_friendly_id?
    new_record? || first_name_changed? || last_name_changed?
  end

  private

  def set_name
    "#{self.first_name.capitalize} #{self.last_name[0].capitalize}."
  end
end

希望这有帮助!