2012-03-29 54 views
4

我在将我的对象生成的JSON表示法传递给我的Sinatra应用程序时遇到问题。我有两个问题:为Sinatra生成JSON

  • 我有2类使用Sequel gem映射到数据库。当他们生成JSON时,它可以正常执行。
  • 我有一个名为注册的自定义类,它用一个附加字段映射其中一个类。我们的目标是产生JSON出这和使用黄瓜(测试目的)

负责处理请求的应用程序代码已经定义的以下函数JSON传递给应用程序:

post '/users' do 
    begin 
    hash = JSON.parse(self.request.body.read) 
    registration = Registration.new.from_json(@request.body.read) 
    registration.user.country = Database::Alaplaya.get_country_by_iso_code(registration.user.country.iso_code) 
    return 400 unless(registration.is_valid?) 
    id = Database::Alaplaya.create_user(registration.user) 

    # If the registration failed in our system, return a page 400. 
    return 400 if id < 1 
end 
  • 问题1:我无法使用params散列。它存在,但只是一个空的散列。为什么?
  • 问题2:我无法反序列化类自身生成的JSON。为什么?

的注册类看起来是这样的:

require 'json' 

class Registration 
    attr_accessor :user, :project_id 

    def to_json(*a) 
    { 
     'json_class' => self.class.name, 
     'data'   => [@user.to_json(*a), @project_id] 
    }.to_json(*a) 
    end 

    def self.json_create(o) 
    new(*o['data']) 
    end 

    # Creates a new instance of the class using the information provided in the 
    # hash. If a field is missing in the hash, nil will be assigned to that field 
    # instead. 
    def initialize(params = {}) 
    @user = params[:user] 
    @project_id = params[:project_id] 
    end 

    # Returns a string representing the entire Registration. 
    def inspect 
    "#{@user.inspect} - #{@user.country.inspect} - #{@project_id}" 
    end 

    # Returns a boolean valid representing whether the Registration instance is 
    # considered valid for the API or not. True if the instance is considered 
    # valid; otherwise false. 
    def is_valid? 
    return false if @user.nil? || @project_id.nil? 
    return false if [email protected]_a?(User) || [email protected]_id.is_a?(Fixnum) 
    return false if [email protected]_valid? 
    true 
    end 
end 

我不得不实施方法才能正确地生成JSON输出。当我在控制台运行此我得到下面的输出生成的:

irb(main):004:0> r = Registration.new(:user => u, :project_id => 1) 
=> new_login - nil - 1 
irb(main):005:0> r.to_json 
=> "{\"json_class\":\"Registration\",\"data\":[\"{\\\"json_class\\\":\\\"User\\\ 
",\\\"login\\\":\\\"new_login\\\"}\",1]}" 

它看起来像有效的JSON给我。但是,当我将这个POST到应用程序服务器并尝试解析它时,JSON会抱怨至少需要2个八位字节并拒绝反序列化对象。

+0

你有什么期望在params哈希表? POST请求的主体是JSON,而不是表单参数。所以除非你在URI中传递一个查询字符串,否则没有东西可以放入参数中。 注册#from_json定义在哪里? 当你说你不能反序列化JSON时,JSON的外观如何,以及你遇到的错误是什么? – 2012-03-29 13:08:40

+0

这不总是发生,但有时我收到一个错误,说像__JSON需要至少2个八位字节___时调用示例** JSON.parse(registration.to_json)**。我目前有一个手动执行,似乎工作。 – 2012-03-29 13:13:56

+0

当您尝试解析空字符串时,会出现错误“JSON需要至少2个八位字节”。在调用结束时使用救援就像这样'JSON.parse(my_string)rescue {}' 另外 - 您是否将Sequel用作您的ORM? – jacobsimeon 2012-03-29 17:12:25

回答

4

如果您使用的续集作为你的ORM,尝试这样的事情:

在你的模型:

class Registration < Sequel::Model 
    many_to_one :user 
    many_to_one :project 
    plugin :json_serializer 
end   

服务器:

before do 
    @data = JSON.parse(request.body.read) rescue {} 
end 

post '/users' do 
    @registration = Registration.new @data 
    if @registration.valid? 
    @registration.save 
    @registration.to_json #return a JSON representation of the resource 
    else 
    status 422 #proper status code for invalid input 
    @registration.errors.to_json 
    end 
end 

我想你可能会过于复杂您的注册过程。如果HTTP操作是POST /users那么为什么不创建一个用户?似乎创建registration过于复杂。除非你的用户已经存在,在这种情况下POST /users将是不正确的。如果你真的打算做的是用户添加到项目中,那么你应该PUT /projects/:project_id/users/:user_id和行动将是这个样子:

class User < Sequel::Model 
    many_to_many :projects 
end 
class Project < Sequel::Model 
    many_to_many :users 
end 
#make sure your db schema has a table called users_projects or projects_users 

put '/projects/:project_id/users/:user_id' do 
    #find the project 
    @project = Project.find params[:project_id] 
    raise Sinatra::NotFound unless @project 
    #find the user 
    @user = Project.find params[:project_id] 
    raise Sinatra::NotFound unless @user 
    #add user to project's users collection 
    @project.add_user @user 
    #send a new representation of the parent resource back to the client 
    #i like to include the child resources as well 
    #json might look something like this 
    #{ 'name' : 'a project name', 'users' : ['/users/:user_id', '/users/:another_user_id'] } 
    @project.to_json 
end