如何在相同的Rails应用程序中序列化和传递ActiveRecord实例?

时间:2010-02-20 18:24:58

标签: ruby-on-rails ruby json serialization

主要思想是我有几个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请求中完成所有操作,否则我想避免使用它。

  • 格式无关紧要。无论什么方便。
  • 不需要发送ID,因为其他应用只会在“聚合”系统中创建记录并分配新ID。
  • 需要保留层次结构(例如“Hey other Rails应用程序,我有流派,每个类型都有一个艺术家,每个艺术家都有一个专辑,每个专辑都有歌曲”等。)

4 个答案:

答案 0 :(得分:3)

使用active resource直接在远程应用中创建帖子。

http://railscasts.com/tags/19

答案 1 :(得分:3)

您可以使用以下几种方法来实现此目的:

有效资源

正如其他人已经回答的那样,您可以使用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请求)

答案 2 :(得分:1)

不完全是答案,但有几点想法:

  • 您可以使用帖子致电to_json,而不是Marshal.dump
  • 您可以创建一个控制器,通过远程导轨实例Marshal.load上的HTTP接收此类序列化数据并保存它们(可能需要一些代码来解决各种冲突)。

我不确定编组将如何处理包含的数据以及远程端需要多少工作来确保干净的导入(哪些记录会破坏某些独特性等),但我会进行一些实验并查看。

BTW,既然您首先提出了问题,我猜标准数据库复制解决方案对您不起作用?

答案 3 :(得分:1)

我有一个类似的用例,我使用 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 }