Ruby on rails Rails 3嵌套属性:如何将匹配记录分配给父模型,而不是每次都创建新记录?

Ruby on rails Rails 3嵌套属性:如何将匹配记录分配给父模型,而不是每次都创建新记录?,ruby-on-rails,ruby-on-rails-3,nested-forms,nested-attributes,Ruby On Rails,Ruby On Rails 3,Nested Forms,Nested Attributes,以下是基本设置: 我有一个订单型号。一个订单有一个地址,它接受:Address的嵌套属性 我有一个基本的订单,要求用户输入地址。这是通过的嵌套字段处理的。一切都很好-新地址都经过验证并分配得很好 但是,问题是,它每次都会创建一个新的地址,即使地址已经存在,并且具有相同的属性 我想修改该行为,以便如果用户输入的地址与现有地址的所有属性匹配,订单将现有地址分配给自身,而不是创建新地址 我尝试过的方法有: 在控制器中,尝试查找具有嵌套属性的现有地址记录(params[:order][:Address\

以下是基本设置:

我有一个
订单
型号。一个
订单
有一个
地址
,它
接受:Address的嵌套属性

我有一个基本的订单,要求用户输入地址。这是通过
的嵌套字段处理的。一切都很好-新地址都经过验证并分配得很好

但是,问题是,它每次都会创建一个新的
地址
,即使
地址
已经存在,并且具有相同的属性

我想修改该行为,以便如果用户输入的地址与现有
地址
的所有属性匹配,订单将现有
地址
分配给自身,而不是创建新地址

我尝试过的方法有:

  • 在控制器中,尝试查找具有嵌套属性的现有地址记录(
    params[:order][:Address\u attributes]
    )。如果存在匹配项,请删除所有嵌套属性并将其替换为
    params[:order][:address\u id]

  • 根本不要为使用
    嵌套的属性,而是覆盖模型中的
    地址=
    方法,然后使用控制器根据参数创建一个新的
    地址
    ,然后将其交给模型

  • 这两种解决方案似乎都有不同程度的混乱。有人能告诉我这是一个控制器还是模型的责任,也许能建议一个优雅的方法来实现这一点


    提前谢谢。

    你试过这样的东西吗

    class Order < ActiveRecord::Base
      # [..]
    
      before_save :replace_existing_address!
    
      def replace_existing_address!
        db_address = Address.where(:city => self.address.city,
                    :street => self.address.street,
                    :number => self.address.number).first
        self.address = db_address if db_address
      end
    
    end
    
    类顺序self.address.city,
    :street=>self.address.street,
    :number=>self.address.number)。首先
    self.address=db\u地址(如果是db\u地址)
    结束
    结束
    
    既然我问这个问题是为了调查解决问题的好方法,我想我会提供我目前使用的解决方案以及发表评论的依据

    在控制器中:

    @new_address = Address.new( params[:order][:address] )
    @order.address = new_address
    @order.update_attributes( params[:order] )
    
    def address=( address )
        return unless address and address.is_a? Address
    
        duplicate_address = Address.where( address_1: address.address_1, 
                                           address_2: address.address_2,
                                           [etc. etc.] ).first
    
        if duplicate_address
            self.address_id = duplicate_address.id
        else
            address.save
            self.address_id = address.id
        end
    end
    
    在模型中:

    @new_address = Address.new( params[:order][:address] )
    @order.address = new_address
    @order.update_attributes( params[:order] )
    
    def address=( address )
        return unless address and address.is_a? Address
    
        duplicate_address = Address.where( address_1: address.address_1, 
                                           address_2: address.address_2,
                                           [etc. etc.] ).first
    
        if duplicate_address
            self.address_id = duplicate_address.id
        else
            address.save
            self.address_id = address.id
        end
    end
    

    正如你所说,这确实是一个:有一个关系,而不是一个:有很多,你不需要像在自己的答案中那样明确地分配地址。毕竟,这就是接受嵌套属性的目的。这条线本身应该起作用:

    @order.update_attributes( params[:order] )
    
    如果不存在,则应创建新地址,并更新现有地址


    您的解决方案可能会起作用,但它a)不会利用accepts_nested_属性,b)会在数据库中留下大量孤立地址。

    是的,这与我使用的重写属性设置器非常相似。我喜欢这种方法,尽管我可能会在创建前将其设置为
    ,这样它就不会在每次修改订单时查询数据库。在接受之前,我想看看人们使用了哪些其他方法,但这似乎是一个非常好的解决方案。而且名称也不完美,可能是
    reuse\u address,我现在不认为孤立地址有什么好处,但这如何解决最初的问题,即这种方法将导致数据库中有多个相同的地址(除了ID之外)?据我所知,
    接受嵌套属性
    不检查是否存在具有相同属性的记录,它只检查是否存在具有相同ID的记录。由于地址在通过订单创建时没有ID,因此每次都会产生一个新地址。