【问题标题】:Generating JSON for Sinatra为 Sinatra 生成 JSON
【发布时间】:2012-04-12 22:05:21
【问题描述】:

我在将生成的对象的 JSON 表示法传递给我的 Sinatra 应用程序时遇到问题。我遇到的问题是双重的:

  • 我有 2 个使用 Sequel gem 映射到数据库的类。当他们生成 JSON 时,一切正常并正确实施。
  • 我有一个名为注册的自定义类,它将其中一个类映射到一个附加字段。目标是从中生成 JSON 并使用 cucumber 将该 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 !@user.is_a?(User) || !@project_id.is_a?(Fixnum)
    return false if !@user.is_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。然而,当我将它发布到应用程序服务器并尝试解析它时,JSON 抱怨至少需要 2 个八位字节并拒绝反序列化该对象。

【问题讨论】:

  • 您希望在 params 哈希中包含什么内容? POST 请求的主体是 JSON,而不是表单参数。因此,除非您在 URI 中传递查询字符串,否则没有任何内容可放入参数中。 Registration#from_json 在哪里定义?当您说无法反序列化 JSON 时,JSON 是什么样的,您遇到的错误是什么?
  • 它并不总是发生,但有时我会收到一个错误,例如 JSON 需要至少 2 个八位字节,例如调用 JSON.parse(registration.to_json)。我目前有一个似乎可行的手动实现。
  • 当您尝试解析空字符串时,会出现错误“JSON 需要至少 2 个八位字节”。像这样在通话结束时使用救援JSON.parse(my_string) rescue {} 另外 - 您是否使用 Sequel 作为您的 ORM?

标签: ruby json sinatra rack


【解决方案1】:

如果您使用 Sequel 作为 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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2011-08-24
    • 1970-01-01
    • 1970-01-01
    • 2011-12-21
    • 2013-09-17
    • 1970-01-01
    • 2016-04-02
    相关资源
    最近更新 更多