2011-02-10 50 views
1

我有一个模型,它使用单表继承和不同类型(学年或学期类型),每种类型都有自己的验证。如果用户试图改变记录的类型,他可以从下拉列表中选择哪个学年类型并进行更改。但是,如果用户更改类型,我无法弄清楚如何使新的类验证运行而不是旧的验证。例如,我的代码如下:如何更改记录的类型并使用类型列在rails中运行正确类的验证?

@school_year = SchoolYear.find(params[:id]) 
respond_to do |format| 
    if SchoolYear::SUBCLASSES.include? params[:school_year]['type'] 
    @school_year[:type] = params[:school_year]['type'] 
    else 
    raise "Invalid type" 
    end 

    if @school_year.update_attributes(params[:school_year]) 
    # done 
    else 
    # validation problem? 
    end 

现在如果当年的类型是学期,并且用户将其更改为季度,我预计QuarterSchoolYear的验证并没有那些学期的运行。我如何修改代码以使其工作?

回答

3

我想你应该在更改类型后重新加载对象。只需给'type'属性赋一个新值就不会改变对象的ruby类。当然,当你在类型改变之后保存对象时,将使用旧的验证。

您可能会尝试更新数据库中的类型属性,然后加载该对象。 喜欢的东西:

[..] 
if type_differs_and_is_acceptable_to_change 
    SchoolYear.update_all(
    ['type = ?', params[:shool_year][:type] ], 
    ['id = ?',@school_year.id ] 
) 
    @school_year = SchoolYear.find(@school_year.id) 
end 
if @school_year.update_attributes... 

一定要具有:这个类在attr_accessible不会打字。

除此之外,我发现改变物体的类型有点令人不安,但这可能只是我个人的恐惧。 :)

1

您需要使用正确类型的模型实例化以运行验证。我没有看到一个办法做到这一点,除非使用新型保存和再次找到它:

new_type = params[:school_year]['type'] 
@school_year[:type] = new_type 
@school_year.save! 
@school_year = new_type.constantize.find(@school_year.id) 
@school_year.update_attributes(params[:school_year]) 

你可能希望把这个交易,所以你可以,如果update_attributes回滚类型的变化失败。

+0

它在第4行的代码中失败,因为它实际上并未将其保存在事务中,因此查找失败。 – umar 2011-02-28 10:29:43

+0

你的意思是“它实际上并没有将它保存在交易中”是什么意思? `保存!`会引发异常吗? – zetetic 2011-02-28 19:06:56

3

这是旧的,但是清理并改进@Arsen7的建议,重新加载对象作为其新类型的最佳方法是使用以下ActiveRecord方法(这是出于这个原因),并且它不会' t要求您在更改其类型后保存该对象。通过这种方式,您不会触及数据库两次:

[..] 
if type_differs_and_is_acceptable_to_change 
    @school_year.type = params[:school_year][:type] 
    @school_year = @school_year.becomes(@school_year.type.constantize) 
end 
if @school_year.update_attributes...