Как я могу сериализовать и передавать экземпляры ActiveRecord через идентичные приложения Rails? - PullRequest
4 голосов
/ 20 февраля 2010

Основная идея заключается в том, что у меня есть несколько рабочих экземпляров приложения Rails, а затем основной агрегат

Я хочу сделать что-то подобное со следующим псевдоподексом

posts = Post.all.to_json( :include => { :comments => { :include => :blah } })
# send data to another, identical, exactly the same Rails app

# ...
# Fast forward to the separate but identical Rails app:
# ...

# remote_posts is the posts results from the first Rails app
posts = JSON.parse(remote_posts)  
posts.each do |post|
  p = Post.new
  p = post
  p.save
end

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

  • Формат не имеет значения. Что бы ни делало это удобным.
  • Идентификаторы не нужно отправлять, потому что другое приложение будет просто создавать записи и назначать новые идентификаторы в «совокупной» системе.
  • Иерархия должна быть сохранена (например, «Привет, другое приложение Rails, у меня есть жанры, и у каждого жанра есть исполнитель, и у каждого исполнителя есть альбом, и у каждого альбома есть песни» и т. Д.)

Ответы [ 4 ]

3 голосов
/ 18 марта 2010

Есть несколько опций, которые вы можете реализовать, чтобы заставить это работать:

Активный ресурс

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

Контроллер получения

Во втором приложении rails может быть контроллер, который получает данные и создает из них записи.

class RecordReceiver < ActiveRecord::Base
  def create
    params[:data][:posts].each do |p|
      Post.create(p)
    end
  end
end

Вы можете поместить пространство имен этого контроллера в пространство имен «API», которое является довольно чистым решением при правильной реализации.

Совместное использование базы данных

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

Две базы данных в каждом приложении

Вы можете реализовать несколько баз данных в каждом приложении, например так:

#Add to database.yml
other_development:
  adapter: mysql
  database: otherdb_development
  username: root
  password:
  host: localhost

other_production:
  adapter: mysql
  database: otherdb_production
  username: root
  password:
  host: localhost

Затем определите ваши модели следующим образом:

class Post < ActiveRecord::Base

end

class PostClone < ActiveRecord::Base
  establish_connection "other_#{RAILS_ENV}"
end

Теперь ваша модель Clone будет указывать на текущую базу данных, а модель PostClone будет указывать на другую базу данных. Имея доступ к обоим, вы можете копировать данные в любое время с помощью основных методов модели.

Заключение

Поскольку вы не хотите использовать ActiveResource, я бы порекомендовал вам просто делиться базой данных между приложениями. Если это невозможно, попробуйте две модели, каждая из которых будет иметь свою базу данных. Наконец, получающий контроллер является допустимым, хотя и более медленным вариантом (так как он должен выполнять HTTP-запрос поверх запросов к базе данных)

3 голосов
/ 20 февраля 2010

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

http://railscasts.com/tags/19

1 голос
/ 11 марта 2010

У меня похожий вариант использования, и я использую ActiveResource . Если вы хотите сохранить содержащиеся в нем объекты, это хороший выбор. ActiveResource предоставляет вам выбор JSON или XML в качестве проводного формата.

Вы можете упаковать все свои записи в один запрос. На принимающей стороне вы можете обработать запрос за одну транзакцию.

Исходное приложение

  class PostsController < ApplicationController

    def synch
      @posts = Post.all(:conditions => {...})
      #
      # Multiple posts and their child objects uploaded in one HTTP call.
      #
      Remote::Post.upload(@posts)                       
    end
  end

  # ActiveResource model for remote Post
  module Remote
    class Post < ActiveResource::Base
      self.site = "http://host:3000/"
      def self.upload posts
        # pass :include option to to_xml to select
        # hierarchy.
        body = posts.to_xml(:root => 'posts', :except => [:id]
                 :include => { :genres =>{ :except => [:id],
                                 :artists => { :except => [:id],
                                    :albums => { :except => [:id],
                                       :songs => {:except => [:id] }
                                    }
                                 }
                               }
                             }
        )
        post(:upload, {}, body) 
      end
    end
  end

Приложение назначения

  class PostsController < ApplicationController  
    def upload
      #
      # Multiple posts and their child objects are saved in one call.
      #
      Posts.create(params[:posts])                                    
    end
  end

  class Post < ActiveRecord::Base
    has_many :genres
    accepts_nested_attributes_for ::genres
  end

  class Genre < ActiveRecord::Base
    has_many :artists 
    accepts_nested_attributes_for :artists 
  end

  class Artist < ActiveRecord::Base
    has_many :songs
    accepts_nested_attributes_for :songs
  end

  class Album < ActiveRecord::Base
    has_many :albums
    accepts_nested_attributes_for :albums
  end


  class Songs < ActiveRecord::Base
  end

Другие варианты для более быстрой обработки в месте назначения: ARExtensions . Этот камень поддерживает массовые вставки.

Маршрут назначения

map.resources :posts, :collection => { :upload => :post }
1 голос
/ 20 февраля 2010

Не совсем ответ, но пара идей:

  • Вместо вашего to_json вы можете звонить Marshal.dump со своими сообщениями.
  • Вы можете создать контроллер, который будет получать такие сериализованные данные через HTTP на удаленном экземпляре rails, Marshal.load и сохранять их (возможно, с некоторым кодом для решения всех видов коллизий).

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

Кстати, так как вы задали вопрос в первую очередь, я думаю, стандартные решения для репликации баз данных у вас не работают?

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