Вложенные атрибуты Rails 3: Как я могу присвоить соответствующую запись родительской модели вместо того, чтобы каждый раз создавать новую запись? - PullRequest
4 голосов
/ 17 июля 2011

Вот основные настройки:

У меня есть Order модель. У Order есть один Address и он accepts_nested_attributes_for :address.

У меня есть базовая форма заказа, где я прошу пользователя ввести ее адрес. Это обрабатывается с nested_fields_for. Все отлично работает - новые адреса проверены и назначены красиво.

Однако проблема в том, что создает новый Address каждый раз , даже если Address уже существует с идентичными атрибутами.

Я хотел бы изменить поведение так, чтобы, если введенный пользователем адрес совпадал со всеми атрибутами существующего Address, порядок назначал существующий Address самому себе, а не создавал новый один.

Методы, которые я пробовал:

  1. В контроллере попробуйте найти существующую запись адреса с вложенными атрибутами (params[:order][:address_attributes]). Если совпадение существует, удалите все вложенные атрибуты и замените их на params[:order][:address_id].

  2. Ни в коем случае не используйте nested_attributes_for, а вместо этого переопределите метод address= в модели, затем просто используйте контроллер для создания нового Address на основе параметров и затем передайте его модель.

Оба эти решения кажутся различными степенями беспорядка. Может ли кто-нибудь объяснить мне, является ли это обязанностью контролера или модели, и, возможно, предложить элегантный способ сделать это?

Заранее спасибо.

Ответы [ 3 ]

1 голос
/ 17 июля 2011

Вы пробовали что-то подобное?

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
0 голосов
/ 17 июля 2011

Если вы действительно говорите как отношение has_one, а не как has_many, вам не нужно явно назначать адрес, как вы делаете это в своем ответе.В конце концов, для этого и есть acceptpts_nested_attributes.Эта строка сама по себе должна работать:

@order.update_attributes( params[:order] )

Это должно создать новый адрес, если его не существует, и обновить существующий.

Ваше решение может работать, но оно а) не использует Accepts_nested_attributes и б) оставит много потерянных адресов в вашей базе данных.

0 голосов
/ 17 июля 2011

Поскольку я спрашиваю это как обзор хороших способов сделать это, я решил, что предложу решение, которое я использую в настоящее время, а также основу для комментариев.Контроллер:

@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
...