Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/ruby-on-rails/54.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Ruby on rails Rails RESTful to_xml-如何实现连接?_Ruby On Rails_Xml_Rest - Fatal编程技术网

Ruby on rails Rails RESTful to_xml-如何实现连接?

Ruby on rails Rails RESTful to_xml-如何实现连接?,ruby-on-rails,xml,rest,Ruby On Rails,Xml,Rest,在阅读了Leonard Richardson和Sam Ruby的《RESTful Web服务》一书之后,我觉得rails的to_xml方法并不像它应该的那样RESTful。具体来说,本书介绍了面向资源的体系结构,其宗旨之一是连通性:资源的表示不仅应该包含资源的数据,还应该包含与其他资源的链接 然而,当rails构建资源时,它通过遵从[model]#to_xml来实现对xml表示的请求。此方法无法访问普通路径帮助程序,因此指向其他资源的任何链接都仅由其ID指示,而不是由其URI指示 我现在已经解决

在阅读了Leonard Richardson和Sam Ruby的《RESTful Web服务》一书之后,我觉得rails的to_xml方法并不像它应该的那样RESTful。具体来说,本书介绍了面向资源的体系结构,其宗旨之一是连通性:资源的表示不仅应该包含资源的数据,还应该包含与其他资源的链接

然而,当rails构建资源时,它通过遵从[model]#to_xml来实现对xml表示的请求。此方法无法访问普通路径帮助程序,因此指向其他资源的任何链接都仅由其ID指示,而不是由其URI指示

我现在已经解决了这个问题,但解决方案似乎不是很可靠:给定一个包含嵌套雇员的雇主资源,以下代码(某种程度上)将URI添加到其xml序列化中:

class Employee < ActiveRecord::Base

  include ActionController::UrlWriter

  belongs_to :employer

  def to_xml(options = {})
    options[:procs] = [ Proc.new {|options| options[:builder].tag!('uri', employer_employee_path(employer, self)) } ]
    if options[:depth].nil?
      options[:depth] = 1
    end
    if options[:depth] != 0
      options[:depth] -= 1;
      options[:include] = [:employer]
    end
    super(options)
  end
end

class Employer < ActiveRecord::Base

  include ActionController::UrlWriter

  has_many :employees

  def to_xml(options = {})
    options[:procs] = [ Proc.new {|options| options[:builder].tag!('uri', employer_path(self)) } ]
    if options[:depth].nil?
      options[:depth] = 1
    end
    if options[:depth] != 0
      options[:depth] -= 1;
      options[:include] = [:employees]
    end
    super(options)
  end
end
class Employee
UrlWriter允许我正确创建资源的路径(但不是完整的uri。必须由web服务的客户端将域粘贴到路径上)。现在,模型负责自己的uri,并负责包含任何连接资源的表示。我使用:depth选项来避免无休止的递归


这种方法是可行的,但正如前面所述,它似乎并不完全正确,因为存在所有的重复。是否有其他人也有同样的问题?是否有其他人对如何在xml表示中获取URI有更好的想法?

您可以使用
:methods
选项来包含其他值。比如说

# in controller
employer.to_xml(:include => :employees, :methods => [:uri])

class Employee < ActiveRecord::Base
  include ActionController::UrlWriter
  belongs_to :employer

  def uri(options = {})
    polymorphic_path([employer, self])
  end
end

class Employer < ActiveRecord::Base
  include ActionController::UrlWriter
  has_many :employees

  def uri(options = {})
    polymorphic_path(self)
  end
end
然后您可以在控制器中为模型设置uri。不幸的是,这也相当混乱

employer.uri = polymorphic_path(employer)
employer.employees.each { |e| e.uri = polymorphic_path([employer, e]) }
employer.to_xml(:include => :employees, :methods => [:uri])

是的。。。这属于视图。为什么不使用内置的XML生成器呢

#in controller
respond_to do |format|
  format.xml  # show.xml.builder
end
然后简单地创建一个show.xml.builder文件,如下所示

# in show.xml.builder
xml.instruct!
xml.employer do
  xml.name @employer.name
  ...
  xml.uri polymorphic_path(employer)
end

在你的控制器中放一堆构建器代码对我来说有点不满意。另外,您不能使用Array#to_xml,这非常简洁方便

像这样的怎么样:

#things_controller.rb 
def index
  render :xml=>Thing.all.to_xml(:thing_url=>thing_url('#{self.code}'))
end

#thing.rb
def to_xml(options={})
  if thing_url = options[:thing_url]
    thing_url = eval('"'+CGI.unescape(options.delete(:thing_url))+'"') 
  end
  super do |builder|
    builder.tag!('thing-url', thing_url) if thing_url
  end
end

我同意,在模型中包含UrlWriter是一件麻烦事。甚至UrlWriter名称空间也表明,它在逻辑上是控制器的一部分,而不是模型。我想最主要的问题是,在xml的情况下,模型负责自己的表示。我认为XML表示属于视图层,如果它需要包含URL路径等,这是有意义的。您可能会创建一个通用的render_XML方法,其行为类似于_XML,但在视图范围内运行,因此它可以访问所有帮助程序。顺便说一句,如果您最终在每个模型中都调用“include ActionController::UrlWriter,最好只在ActiveRecord::Base中调用一次。如果有很多路线的话,启动时间会好得多(但是,我一般不建议这样做)。
#things_controller.rb 
def index
  render :xml=>Thing.all.to_xml(:thing_url=>thing_url('#{self.code}'))
end

#thing.rb
def to_xml(options={})
  if thing_url = options[:thing_url]
    thing_url = eval('"'+CGI.unescape(options.delete(:thing_url))+'"') 
  end
  super do |builder|
    builder.tag!('thing-url', thing_url) if thing_url
  end
end