开发者

Rails: Keeping all the ActiveRecord "validates" lines in a separate file?

UPDATE (4th Dec 2010):

I realized that each validates line is actually a method call (obviously) so requiring them like this wasn't exactly doing as I expected.

This works, but I'm not sure it's correct (fully qualify the Auction class name):

class Auction::Validations
  Auction.validates :status, :presence => true,
                     :inclusion => { :in => [
                        Auction::CREATING,
                        Auction::OPEN,
                        Auction::PENDING,
                        Auction::CANCELLED,
                        Auction::SUSPENDED,
                        Auction::EXPIRED,
                        Auction::CLOSING_COMPLETED,
                        Auction::CLOSING_WON,
                        Auction::COMPLETED,
                        Auction::WON,
                        Auction::NEGOTIATING,
                        Auction::IN_ESCROW
                     ] }
  Auction.validates :user,   :presence => true
  Auction.validates :url,    :presence => true,
                     # FIXME: Move this to a URLValidator and do :url => true
                     :format => /^https?:\/\/[a-z0-9-]+(\.[a-z0-9-])*\开发者_JS百科.[a-z0-9]+\/.*/i
  Auction.validates :title,  :presence => true,
                     :length => { :maximum => 255 }
  Auction.validates :description,  :presence => true
  Auction.validates :reserve, :numericality => { :greater_than_or_equal_to => :minimum_bid }
end

When this is required (require 'auction/validations) into the Auction class, it does the correct thing.

Original Question follows:

A couple of my model classes are getting a little cluttered with all these "validates" calls, so I thought I'd be able to move them into a separate class and 'require' that, but it doesn't seem to work.

class Auction < ActiveRecord::Base
  require 'auction/validations'
  ...

class Auction::Validations
  include ActiveModel::Validations

  validates :status, :presence => true,
                     :inclusion => { :in => [
                        ... snip ...
                     ] }
  validates :user,   :presence => true
  validates :url,    :presence => true,
                     # FIXME: Move this to a URLValidator
                     :format => /^https?:\/\/[a-z0-9-]+(\.[a-z0-9-])*\.[a-z0-9]+\/.*/i
  validates :title,  :presence => true,
                     :length => { :maximum => 255 }
  validates :description,  :presence => true
  validates :reserve, :numericality => { :greater_than_or_equal_to => :minimum_bid }

  validates_each :status, :on => :update do |auction, status_attr, value|
    if auction.state_machine.current_state != value
      # FIXME: Raise an Exception instead; this is a developer error, not a user error
      auction.errors.add status_attr, "Status cannot be changed directly"
    end
  end
end

It doesn't error, but the validates_each doesn't execute the block at all (tested by adding a puts "here"), and the numericality check doesn't work any longer.

With the body of this class blindly copied back into the Auction class again everything works.

Am I misunderstanding what the "require" will do with these validations?

EDIT:

In fact, none of the validations are working. Not just those two. Hmmm.


I'm not sure if this is right but it somehow works for me:

module MyValidations
  module User
    def self.included(base)
      base.validates_presence_of :firstname
    end
  end end

Then u can call

User.class_eval do
  include MyValidations::User
end

Hope that helps.


Put at the end of Auction::Validations:

Auction.send :extend, Auction::Validations

and at the end of Auction put that require line.


Why just not include your module ?

module Auction::Validations
  extend ActiveSupport::Concern
  def included(base)
  validates :status, :presence => true,
                     :inclusion => { :in => [
                        ... snip ...
                     ] }
  validates :user,   :presence => true
  validates :url,    :presence => true,
                     # FIXME: Move this to a URLValidator
                     :format => /^https?:\/\/[a-z0-9-]+(\.[a-z0-9-])*\.[a-z0-9]+\/.*/i
  validates :title,  :presence => true,
                     :length => { :maximum => 255 }
  validates :description,  :presence => true
  validates :reserve, :numericality => { :greater_than_or_equal_to => :minimum_bid }

  validates_each :status, :on => :update do |auction, status_attr, value|
    if auction.state_machine.current_state != value
      # FIXME: Raise an Exception instead; this is a developer error, not a user error
      auction.errors.add status_attr, "Status cannot be changed directly"
    end
  end
  end
end


In Rails 4 this is easy. Use model concerns.

# put this into: app/models/concerns/auction/validations.rb
class Auction
  module Validations
    extend ActiveSupport::Concern

    included do
      validates :status, presence: true
    end
  end
end

class Auction
  include Validations

  # other model code...
end
0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜