Search code examples
ruby-on-railsrubyruby-on-rails-plugins

Ruby on Rails plugin - Adding validation in class doesn't work properly


I made a small DRY plugin that I want to use in some of my classes (like theatre, coffeeshop, restaurant, etc) later on. All those classes consist of an address and therefore, I made an Address model plugin with an act_as_address method that are to be called by those classes to avoid writing duplicate code.

The classes will consist of some validations on the address fields (like presence and length) and I used class_eval inside the act_as_address in the Address model to write those validations to the classes. However, it does not seem to work.

Here is my code and tests:

# structure.sql
create table addresses (
  some_info varchar(25)
  # other attrs
);

create table theatres (
  id integer,
  primary key (id)
) inherits (addresses);


# act_as_address.rb
module Address
  module ActsAsAddress
    extend ActiveSupport::Concern

    include do
    end

    module ClassMethods
      def acts_as_address
        class_eval do <<-EVAL
        validates :some_info, presence: true
        # some other validations, methods etc.
        EVAL
        end
      end
    end
  end
end

ActiveRecord::Base.send :include, Address::ActsAsAddress

# theatre.rb
class Theatre < ActiveRecord::Base
  acts_as_address
end

# address.rb
require 'address/acts_as_address'

module Address
end

# acts_as_address_test.rb
require File.expand_path('../test_helper', __FILE__)

class ActsAsAddressTest < ActiveSupport::TestCase
  test "should not be valid" do
    assert_not Theatre.create(:some_info => nil).valid?, 
      "some_info was valid with nil value"
  end
end

And the result of the test is as following:

  1) Failure:
ActsAsAddressTest#test_should_not_be_valid [acts_as_address_test.rb:16]:
some_info was valid with nil value

Could anyone help me out here? Is class_eval the problem here? I am using Ruby on Rails 4.


Solution

  • You may be able to do this:

    module Address
      module ActsAsAddress
        extend ActiveSupport::Concern
    
        module ClassMethods
          def acts_as_address
            validates :some_info, presence: true
          end
        end
      end
    end