【发布时间】:2012-03-05 02:55:14
【问题描述】:
我想做的是定义一个有效值列表,然后在相关表上添加新角色时根据该值列表进行验证。
让我举一个具体的例子:
假设我有一个“就业”表,其中包含以下字段:
user_id (tied to a user table)
employer_id (tied to an employer table)
position_id (tied to a position table)
details
efbegdt
efenddt
当用户向该表添加新行时,我想确保其他表中已经存在雇主 ID 和职位 ID,并且如果在任一情况下都不是这种情况,则不允许保存。
目前我看到的解决方案是这样的:
class Employment < ActiveRecord::Base
EMPLOYERS = ['Google', 'Yahoo', 'Microsoft']
POSITIONS = ['Web Developer', 'Database Admin', 'QA']
validates_inclusion_of :employer_id, :in => EMPLOYERS
validates_inclusion_of :position_id, :in => POSITIONS
end
但这种方法不够灵活,无法容纳潜在的数千名雇主和职位,如果用户当前不存在雇主,它也不能提供一种简单的方法来允许用户添加新的有效条目。
我也见过这种方法:
class Employment < ActiveRecord::Base
validate :employer_exists
protected
def employer_exists
ids = Employer.all.map(&:id)
if !employer_id.blank? && !ids.member?(employer_id)
errors.add(:employer_id, "invalid employer")
end
end
end
这更接近我想要的,但是当我使用 rspec 进行测试时,检查雇主表上的新行是否有效失败:
Failure/Error: it { should be_valid }
expected valid? to return true, got false
这个问题有“最佳实践”解决方案吗?
更新
只需添加另一个示例,详细说明所有设置。在此示例中,用户可以将多个电子邮件地址存储在电子邮件表中,但每种类型(个人、工作、学校等)限制为一个地址。另一个表 email_dfn 定义了所有有效类型:
迁移文件
class CreateEmailDfns < ActiveRecord::Migration
def change
create_table :email_dfns do |t|
t.string :short_description
t.string :long_description
t.timestamps
end
end
end
和
class CreateEmails < ActiveRecord::Migration
def change
create_table :emails do |t|
t.integer :user_id
t.integer :email_dfn_id
t.string :value
t.text :notes
t.timestamps
end
add_index :emails, [:user_id, :email_dfn_id]
end
end
型号
class Email < ActiveRecord::Base
attr_accessible :value, :notes, :email_dfn_id
belongs_to :user
belongs_to :email_dfn
validates_associated :email_dfn
valid_email_regex = /\A[\w+\-.]+@[a-z\d\-.]+\.[a-z]+\z/i
validates :value, presence: true,
length: { maximum: 256 },
format: { with: valid_email_regex },
uniqueness: { case_sensitive: false }
validates :user_id, presence: true
validates :email_dfn_id, presence: true
end
和
class EmailDfn < ActiveRecord::Base
attr_accessible :short_description,
:long_description,
validates_uniqueness_of :short_description,
:long_description
has_many :emails
end
测试
require 'spec_helper'
describe Email do
let(:user) { FactoryGirl.create(:user) }
before { @email = user.emails.build(email_dfn_id: 1,
value: "personal_email@test.com",
notes: "My personal email address") }
subject { @email }
it { should respond_to(:value) }
it { should respond_to(:notes) }
it { should respond_to(:email_dfn_id) }
it { should respond_to(:user_id) }
it { should respond_to(:user) }
its(:user) { should == user }
it { should be_valid }
describe "when user id is not present" do
before { @email.user_id = nil }
it { should_not be_valid }
end
describe "when email id is invalid" do
before { @email.email_dfn_id = 999 }
it { should_not be_valid }
end
end
在当前设置中,最后一次测试(设置 email_dfn_id = 999,无效代码)失败。
【问题讨论】:
标签: ruby-on-rails model controller