Как сравнить объект activerecord с новым объектом и обновить его, если оно равно в Rails 3? - PullRequest
0 голосов
/ 07 апреля 2011

Я пытаюсь выяснить, есть ли способ сделать это в Rails более эффективно.

Существует довольно долгая настройка для этого вопроса, поэтому, пожалуйста, потерпите меня.Допустим, у меня есть модели Клиент, Телефон, Адрес

Вот примеры миграций, чтобы дать вам представление:

class CreatePhones < ActiveRecord::Migration
  def self.up
    create_table :phones do |t|
      t.integer     :country_prefix, :limit => 3
      t.integer     :area_prefix,    :limit => 5
      t.integer     :number,         :limit => 7
      t.integer :category_id
      t.references  :phonable, :polymorphic => true
      t.timestamps
    end
  end
end

class CreateAddress < ActiveRecord::Migration
  def self.up
    create_table :addresses do |t|
      t.string  :address_line_1
      t.string  :address_line_2
      t.string  :address_line_3
      t.string  :city
      t.string  :state
      t.string  :zip
      t.string  :country
      t.string  :attn
      t.integer :category_id
      t.references  :addressable, :polymorphic => true
      t.timestamps
    end
  end
end
class CreateCategories < ActiveRecord::Migration
  def self.up
    create_table :categories do |t|
          t.string  :name
          t.string  :code         
          t.integer :category_id  # Every subcategory has a category: i.e. phone has work, fax,mobile

          t.timestamps
    end
  end
end

class CreateCustomers < ActiveRecord::Migration
  def self.up
    create_table :customers do |t|
      t.string      :code                            , :limit => 20                         , :null => false 
      t.string      :name                                                                   , :null => false  
      t.string      :billing_name                    
      t.integer     :preferred_shipping_method_id      
end
end

Вот модели и отношения:

class Customer < ActiveRecord::Base
  belongs_to :preferred_shipping_method , :class_name => "Category", :foreign_key => :preferred_shipping_method_id

  has_many :addresses,  :as => :addressable,  :include => :category, :dependent => :destroy
  has_many :phones,     :as => :phonable,     :include => :category, :dependent => :destroy
end

class Category < ActiveRecord::Base
  has_many :addresses
  has_many :phones
  has_many :customer_by_shipping_methods, :class_name => "Customer", :foreign_key => :preferred_shipping_method_id
  has_many :subcategories, :class_name  => "Category", :foreign_key => :category_id
  belongs_to :category, :class_name => "Category"
end

class Address < ActiveRecord::Base
  belongs_to :category
  belongs_to :addressable, :polymorphic => true

end

class Phone < ActiveRecord::Base
  belongs_to :category
  belongs_to :phonable, :polymorphic => true
end

Вот вопрос.

Допустим, у меня есть запись клиента с кучей телефонов (мобильный, рабочий) и адреса (биллинг, доставка).

old = Customer.where(:code => "ABC").first

Затем я создаюили импортирование (из устаревшей БД) другого объекта клиента

new = Customer.new
new.code = "ABC"
new.phones.build(:number => "12345567") 

и т. д.

Затем я хочу сравнить информацию о старом клиенте с информацией о новом клиенте и на основе этого обновления старой информации о клиенте.

Примерно так:

if old.eql?(new) # this should compare not only, name & code and such but also polymorphic associations

  old.update_with(new) # this should update old info attributes with new if there is new info, or if update / add to one of the associations
  old.save # 
else
  new.save
end

Таким образом, вопрос в том, существует ли КОНВЕНЦИОННЫЙ способ в Rails 3 делать то, что я описываю в комментариях?

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

class Customer < ActiveRecord::Base

  def hash
    %{#{ name }#{ code }}.hash # There is a lot more here of course
  end

  def eql?(other)
    hash == other.hash
  end

def update_with(other)
  name = other.name
  code = other.code
  etc ....
end    



end

1 Ответ

0 голосов
/ 07 апреля 2011

Ладно, не похоже, что есть стандартное решение, так что вот что я придумала, если кто-то еще его ищет.

Вы можете переименовывать методы в любом случае, просто вставив это в свою библиотеку libпапка в каком-то .rb файле.(не забудьте упомянуть об этом в environment.rb примерно так: require 'custom_comparisons'

/ lib / custom_comparisons.rb

module ActiveRecord
  class Base

    def comparison_hash
      h = ""
      self.attributes.each_pair do |key, value|
        unless ["id", "updated_at", "created_at"].include?(key)
          h << "#{value}"
        end  
      end  
      h.hash
    end 

    def eql_to?(other)
      comparison_hash == other.comparison_hash
    end

    def differences_from?(other)        
      h = {}
      self.attributes.each_pair do |key, value|
        unless self.method_missing(key) == other.method_missing(key)
          h[key.to_sym] = [self.method_missing(key), other.method_missing(key)]
        end  
      end    
      h
    end    

  end
end

Это можно немного убрать, и мне нужно добавитьРазвертывание связей, но решение есть.

Это делает сравнение и показывает различия между объектами. Теперь я могу обновить атрибуты, которые должны быть обновлены. Добавлю метод обновления и уточню завтра.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...