Cliff Says

Here’s a stab at it. Generate a PaymentType model with a single string field.

rails generate model payment_type name:string

Add the three payment types in seeds.rb, and run rake db:seed.

PaymentType.create(:name => "Check")
PaymentType.create(:name => "Credit card")
PaymentType.create(:name => "Purchase order")

Add a names class method to the PaymentType model.

class PaymentType < ActiveRecord::Base
  def self.names
    all.collect { |payment_type| payment_type.name }
  end
end

Change the validation in the Order model. Initially, one might do this:

validates :pay_type, :inclusion => PaymentType.names

Now I’m a Rails n00b, but as far as I can tell, doing validation that way would fetch the payment types just once from the DB at the moment when Ruby defines the Order model class. What if more payment types are added to the DB after the Order model class has been defined? I don’t believe the above validation would pick up the new payment type entries. Hence, I rewrote the validation to query the DB for the payment types every time the validation is called (at least, I think I did):

validates_each :pay_type do |model, attr, value|
  if !PaymentType.names.include?(value)
    model.errors.add(attr, "Payment type not on the list") 
  end
end
Then, in views/orders/_form.html.erb, replace
<%= f.select :pay_type, Order::PAYMENT_TYPES,
                 :prompt => 'Select a payment method' %>

with

<%= f.select :pay_type, PaymentType.names,
                 :prompt => 'Select a payment method' %>

Wham bam. Added some unit and functional tests too. Works like a charm. I’m not super satisfied with the messy-looking validates_each block, though. Anyone with a more elegant validation?