Передать объект Nokogiri на страницу ERB, а затем вернуться к записи - PullRequest
1 голос
/ 25 августа 2011

Это в Синатре. В моем 'get' я создаю переменную экземпляра, которая является объектом nokogiri, созданным из внешнего XML-файла. Я иду в файл erb и анализирую этот объект nokogiri, чтобы сделать макет страницы. В моем методе публикации мне нужен доступ к тому же объекту nokogiri (я могу вернуться к публикации несколько раз и могу изменить объект nokogiri). Я сделал это, установив скрытую переменную на странице erb, например:

    <input type="hidden" name="test" value= '<%= @test %>' >

Затем в своем посте я создаю объект nokogiri из этой переменной следующим образом:

   @test = Nokogiri::XML(params["test"])

Это казалось неуклюжим, но я не разбираюсь в этом. В любом случае, все работало нормально, за исключением того, что где-то в строке мои встроенные кавычки в xml искажаются. Например, узел в моем файле начинается так:

<property name="blah" value='{"name:foo"}'> </property>

И когда я делаю пут в своем посте params ["test"], я получаю это:

<property name="blah" value="{"name:foo"}"> </property>

(одиночные кавычки стали двойными кавычками) и, наконец, после преобразования его обратно в объект нокогири со следующим кодом:

@test = Nokogiri::XML(params["test"])

Я получаю это:

<property name="blah" value="{"/>name:foo"}"&gt; </root>

Есть ли лучший способ сохранить доступ к объекту? Если нет, то есть ли способ сохранить мои встроенные кавычки (я думаю, что установка скрытой переменной в файле erb - это то, где она будет обработана)

1 Ответ

1 голос
/ 26 августа 2011

Резюме

  1. Кэшируйте документы Nokogiri в константе (например, хэш или модуль), которая передается через запросы (в пределах одного и того же запуска сервера; см. Ниже).
  2. Отправьте только ключ к хешу в вашей форме.
  3. Используйте ключ, чтобы позже вывести документ из константы.

Пример

package_32.xml

<packages><kittens in_box="true">32</kittens></packages>

cache_nokodocs.rb

require 'sinatra'
require 'nokogiri'

module NokoDocs
  @docs_by_file = {}
  def self.[](file)
    @docs_by_file[file] ||= Nokogiri::XML(IO.read(file))
  end
end

get "/xml/:doc" do
  @doc = params['doc']
  @xml = NokoDocs[@doc]
  <<-ENDHTML
  The XML starts with '#{@xml.root.name}'
  <form method="post" action="/">
    <input type="hidden" name="xml" value="#{@doc}">
    <button type="submit">Go</button>
  </form>
  ENDHTML
end

post "/" do
  @xml = NokoDocs[params['xml']]
  @xml.to_s
end

Использование

C:\>curl http://localhost:4567/xml/package_32.xml
 The XML starts with 'packages'
 <form method="post" action="/">
   <input type="hidden" name="xml" value="package_32.xml">
   <button type="submit">Go</button>
 </form>

# simulate post that the web browser does from the command line 
C:\>curl -d xml="package_32.xml" http://localhost:4567/ 
<?xml version="1.0"?>
<packages>
  <kittens in_box="true">32</kittens>
</packages>

В первый раз, когда любой пользователь запрашивает определенный файл XML, он будет загружен в хеш; последующие запросы к этому файлу извлекают его из хэша напрямую, предварительно проанализировав.

Осторожно!

  1. Документы не будут кэшироваться на нескольких экземплярах сервера (например, если вы используете обратный прокси-сервер). Они также не будут кэшироваться при перезапуске сервера. Однако, если это статические файлы на диске, худшее, что может произойти, это то, что конкретному сеансу сервера будет просто необходимо заново создать документ Nokogiri, прежде чем его кэшировать.

  2. Использование имени файла на диске и последующее разрешение пользователю отправить его обратно вам, вероятно, очень опасная вещь. Вместо этого вы можете создать пользовательский или случайный ключ при загрузке документа и его использовании. Например:

    require 'digest'
    module NokoDocs
      @docs_by_file = {}
      def self.from_file(file)
        key = Digest::SHA1( file + rand(100) )
        [
          @docs_by_file[key] ||= Nokogiri::XML(IO.read(file)),
          key
        ]
      end
      def self.from_key(key)
        @docs_by_file[key]
      end
    end
    
    get "/xml/:doc" do
      @xml, @key = NokoDocs.from_file params['doc']
      ...
      "<input type="hidden" name="key" value="#{@key}">"
      ...
    end
    
    post "/" do
      @xml = NokoDocs.from_key params['key']
    end
    
  3. Это потенциальная утечка памяти. Каждый уникальный документ, который запрашивают ваши пользователи, анализируется как большой документ Nokogiri и сохраняется навсегда (до перезагрузки сервера). Возможно, вам понадобится система, которая записывает время последнего доступа и имеет синхронизированное задание, которое периодически выметает элементы, к которым не было доступа в течение некоторого времени.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...