2012-03-29 70 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