Rails自定义验证 - 跨模型的属性的唯一性

时间:2014-03-20 13:15:27

标签: ruby-on-rails

我坚持定义一种自定义验证方法,其目的是验证两个模型中属性的唯一性

我意识到这是错误的代码,但我想在重构之前通过测试

这是一个带有自定义验证的模型,用于检查另一个模型属性,错误未定义的局部变量或方法`params' (要温柔,我还在努力弄清楚RoR)

class Widget < ActiveRecord::Base
  include Slugable
  validates :name, presence: true
  validate :uniqueness_of_a_slug_across_models

  def uniqueness_of_a_slug_across_models
    @sprocket = Sprocket.where(slug: params[:widget_slug]).first
    if @sprocket.present?
      errors.add(:uniqueness_of_a_slug_across_models, "can't be shared slug")
    end
  end  
end

1 个答案:

答案 0 :(得分:1)

您无法访问模型中的params。它属于controller和view。您可以做的是在窗口小部件控制器(而不是常规save)中调用自定义方法,以便将params传递给模型:

class WidgetsController < ActionController::Base
  def create
    @widget = Widget.new(widget_params)

    if @widget.save_with_slug_validation(params)
      redirect_to widgets_path
    else
      render :new
    end
  end
end

并定义它:

class Widget < ActiveRecord::Base
  # ...

  def save_with_slug_validation(params)
    sprocket = Sprocket.find_by(slug: params[:widget_slug])

    if sprocket
      errors.add(:uniqueness_of_a_slug_across_models, "can't be shared slug")
    end

    save
  end

end

我没有测试它,但它应该有用。

P.S。使用Rails 4样式。

UPD

我应该测试一下,抱歉。请使用其他方法。

小部件控制器:

# POST /widgets
# POST /widgets.json
def create
  @widget = widget.new(widget_params)
  @widget.has_sprocket! if Sprocket.find_by(slug: params[:widget_slug])

  respond_to do |format|
    if @widget.save
      format.html { redirect_to [:admin, @widget], notice: 'widget was successfully created.' }
      format.json { render action: 'show', status: :created, location: @widget }
    else
      format.html { render action: 'new' }
      format.json { render json: @widget.errors, status: :unprocessable_entity }
    end
  end
end

小工具模型:

class Widget < ActiveRecord::Base
  include Slugable

  validates :name, presence: true
  validate :uniqueness_of_a_slug_across_models, if: 'has_sprocket?'

  def uniqueness_of_a_slug_across_models
    errors.add(:uniqueness_of_a_slug_across_models, "can't be shared slug")
  end

  def has_sprocket!
    @has_sprocket = true
  end

  def has_sprocket?
    !!@has_sprocket
  end

end

最好移动has_sprocket!has_sprocket?方法,并将其自身验证为Slugable关注点。