Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

ActiveModel::Validations on anonymous class

I'm working on a small DataMapper-like ODM project, and I'm trying to make use of the ActiveModel::Validations component. However, I ran into a problem while writing tests - I'm using anonymous classes to construct my test schemas, however when it comes to running the validators, the ActiveModel::Name class is throwing an error: Class name cannot be blank. You need to supply a name argument when anonymous class given

Here's a simple code example to reproduce:

require 'active_model'

book_class = Class.new do
  include ActiveModel::Validations

  validates_presence_of :title

  def title; ""; end # This will fail validation
end

book_class.new.valid? # => throws error

The exception is only raised when there's a failed validator - I'm guessing the problem happens when it tries to construct the validation error message. So my question is:

  • I did a lot of searching, but couldn't find anyone trying to do something similar. Is this simply not possible with ActiveModel, or is there a workaround I'm not aware of?
like image 383
motns Avatar asked Jan 21 '13 02:01

motns


2 Answers

ActiveModel tries to get the model name (as you see here) when setting up the error messages. The quickest way to get around it (short of giving your anonymous class a name), is to give your class a class method model_name that returns an instance of ActiveModel::Name.

for example

require 'active_model'

book_class = Class.new do
  include ActiveModel::Validations
  def self.model_name
    ActiveModel::Name.new(self, nil, "temp")
  end
  validates_presence_of :title

  def title; ""; end # This will fail validation
end

book_class.new.valid? # => no error
like image 141
Jim Deville Avatar answered Nov 17 '22 03:11

Jim Deville


The error is being thrown in the initialize function of ActiveModel::Name here.

module ActiveModel
  class Name
    def initialize(klass, namespace = nil, name = nil)
      @name = name || klass.name

      raise ArgumentError, "Class name cannot be blank. You need to supply a name argument when anonymous class given" if @name.blank?       
      # ...
    end
  end
end

So rather than defining a class method model_name that returns an ActiveModel::Name, you can define a class method name that returns a String.

require 'active_model'

book_class = Class.new do
  include ActiveModel::Validations
  validates_presence_of :title

  def self.name
    "Book"
  end

  def title; ""; end # This will fail validation
end

book_class.new.valid? # => false
like image 12
hjing Avatar answered Nov 17 '22 03:11

hjing