2010-09-14 87 views
0

我有以下两种模式。他们可以解释如下:ActiveRecord关联:如果关联属性匹配,则创建新的关联或引用

报告有一个report_detail(它决定开始/结束月份)。许多报告可以具有相同的报告细节,但没有两个报告细节可以相同。

class Report < ActiveRecord::Base 
    # attr: name :: String 
    # attr: report_detail_id :: Integer 
    belongs_to :report_detail 
    accepts_nested_attributes_for :report_detail 
end 

class ReportDetail < ActiveRecord::Base 
    # attr: duration :: Integer 
    # attr: starting_month :: Integer 
    # attr: offset :: Integer 
end 

我有关于ReportDetail索引的唯一约束[:持续时间:starting_month,:偏移]

我试图做到这一点是:如果一个新的报告ReportDetail有一个独特的组合attrs(:duration,:starting_month,:offset),创建新的ReportDetail并保存为正常。如果报告具有ReportDetail,现有的ReportDetail具有相同的属性,请将报告的详细信息与此ReportDetail关联并保存报告。

我得到这个由走样二传手上report_detail=使用ReportDetail.find_or_create_by...工作,但它的丑陋(它也只是通过实例化与细节的属性创建新报告创建不必要ReportDetail项,出于某种原因,我无法得到保存使用.find_or_initialize_by...正常工作)。我还在ReportDetail上尝试了before_save来说,如果我匹配其他内容,请将self设置为其他值。显然你不能像这样设置自我。

任何思考最好的方式去做这件事?

看到this gist我现在的二传与别名

+0

你可以发布别名代码吗?也许作为一个要点,并把它连接到这里。这听起来像是在正确的轨道上,但可能有一两个错误。加入了 – 2010-09-14 19:03:37

+0

......这段代码没有错误,它都可以工作,但我正在寻找更好的解决方案。我最大的兴趣是,当你使用上面的要点进行初始化时,它实际上会创建一个ReporDetail。我也无法使它与find_or_initialize_by正常工作,因为关联的保存意味着在此之前发生,所以它不会最终保存关联第一次去 – brad 2010-09-14 20:36:14

回答

1

就在这个问题今天跑覆盖,我的解决方案是基于对object_attributes=方法,它是通过accepts_nested_attributes_for提供,我认为这产生更少的烂摊子,而不是重写的标准关联设置方法。深入rails来源找到这个解决方案,这里是github link。代码:

class Report < ActiveRecord::Base 
    # attr: name :: String 
    # attr: report_detail_id :: Integer 
    belongs_to :report_detail 
    accepts_nested_attributes_for :report_detail 

    def report_detail_attributes=(attributes) 
    report_detail = ReportDetail.find_or_create_by_duration_and_display_duration_and_starting_month_and_period_offset(attrs[:duration],attrs[:display_duration],attrs[:starting_month],attrs[:period_offset]) 
    attributes[:id]=report_detail.id 
    assign_nested_attributes_for_one_to_one_association(:report_detail, attributes) 
    end 
end 

一些解释,如果您提供了一个id,将被视为更新,因此不再创建新的对象。另外我知道这种方法需要加号查询,但目前我找不到更好的解决方案。

而且,好像你必须报告,报告的细节之间的关联HAS_ONE,如果这是你的情况,你可以试试这个:

class Report < ActiveRecord::Base 
     # attr: name :: String 
     # attr: report_detail_id :: Integer 
     has_one :report_detail 
     accepts_nested_attributes_for :report_detail, :update_only=>true 
    end 

Accoring到documentation这应该为你工作。 从Rails3中的文件:

:update_only

允许您指定一个现有的记录可能只被更新。 A 只有当 没有现有记录时才可以创建新记录。此 选项仅适用于一对一 关联,并且 集合关联将被忽略。此选项 默认为关闭。

希望这会有所帮助,无论如何,如果你找到更好的解决方案,请让我知道。

+0

抱歉没有应答/接受,我已经切换到别的东西,没有机会测试,当我做的时候会更新,thx的答案! – brad 2010-09-30 20:46:36