Rails RESTful to_xml - как добиться связности? - PullRequest
2 голосов
/ 10 августа 2009

После прочтения книги Леонард Ричардсона и Сэма Руби «RESTful Web Services» мне кажется, что метод рельсов to_xml не так расслаблен, как должен быть. В частности, в книге представлена ​​ресурсно-ориентированная архитектура, одним из принципов которой является связность: представления ресурса должны содержать не только данные ресурса, но и ссылки на другие ресурсы.

Однако, когда rails строит ресурс, он реализует запросы на представление в формате XML, передавая значение [model] #to_xml. Этот метод не имеет доступа к обычным помощникам пути, поэтому любые ссылки на другие ресурсы указываются только их идентификаторами, а не их URI.

Я уже решил эту проблему, но решение кажется не очень надежным: учитывая ресурс Employer с вложенными сотрудниками, следующий код (вроде) добавляет Uris к их сериализации 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

UrlWriter позволяет мне правильно создать путь к ресурсу (но не к полному URI. Домен должен быть вставлен на путь клиентами моего веб-сервиса). Теперь модели отвечают за свой URI и за включение представления любого подключенного ресурса. Я использую опцию: глубина, чтобы избежать бесконечного повторения.

Этот метод работает, но, как уже говорилось ранее, он не совсем верный, со всем дублированием. У кого-нибудь еще была такая же проблема, и есть ли у кого-то еще лучшее представление о том, как получить uris в представлении xml?

Ответы [ 3 ]

4 голосов
/ 10 августа 2009

Вы можете использовать опцию :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

Обратите внимание, я здесь использую polymorphic_path. Это более общий метод пути, через который вы можете найти больше абстракций.

Тем не менее, я не думаю, что это отличное решение. Включение UrlWriter в модель является грязным и может занять много времени, если у вас большое количество маршрутов. Альтернатива - сделать URI простым методом доступа.

# in model
attr_accessor :uri

И тогда вы можете установить URI для модели (ей) в контроллере. К сожалению, это тоже довольно грязно.

employer.uri = polymorphic_path(employer)
employer.employees.each { |e| e.uri = polymorphic_path([employer, e]) }
employer.to_xml(:include => :employees, :methods => [:uri])
1 голос
/ 31 марта 2010

Помещать кучу кода Builder в свой контроллер мне не нравится. Кроме того, вы не можете использовать 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
1 голос
/ 26 февраля 2010

Да ... это относится к виду. Почему бы не использовать встроенный XML Builder?

#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
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...