Может ли HTTP-составная / смешанная XML-часть быть преобразована в хэш при смешивании с другими частями - PullRequest
0 голосов
/ 24 сентября 2010

Вопрос чуть выше последнего фрагмента кода. Спасибо. (детали среды - конец)

posts_controller.rb

class PostsController < ApplicationController  
def create
    @post = Post.new(params[:post])
    respond_to do |format|
      format.xml { render :xml => @post.to_xml(:include => [ :assets])}
end
end

posts.rb

class Post < ActiveRecord::Base
  has_many    :assets, :as => :attachable, :dependent => :destroy
end

asset.rb

class Asset < ActiveRecord::Base
  belongs_to :attachable, :polymorphic => true
  has_attached_file :data,
                    :url  => "/assets/:id",
                    :path =>":rails_root/assets/:id_partition/:style/:basename.:extension"
  def name
    data_file_name
  end

  def content_type
    data_content_type
  end

  def file_size
    data_file_size
  end
  end

сейчас, когда мы публикуем эту информацию

POST /posts.xml HTTP/1.1
Accept-Encoding: gzip,deflate
Accept: application/xml
Content-Type: application/xml
User-Agent: Jakarta Commons-HttpClient/3.1
Host: localhost:8080
Content-Length: 60

<post><body>postbody</body><title>post_title</title></post>

создается запись и когда я отправляю это

POST /posts.xml HTTP/1.1
Content-type: multipart/mixed; boundary=---------------------------7d226f700d0
Accept: application/xml,text/html, image/gif, image/jpeg, *; q=.2, */*; q=.2
Cache-Control: no-cache
Pragma: no-cache
User-Agent: Java/1.6.0_21
Host: 192.168.0.105:8080
Connection: keep-alive
Content-Length: 1710

-----------------------------7d226f700d0
content-disposition: form-data; name="post[title]"
Content-Length: 10
post_title
-----------------------------7d226f700d0
content-disposition: form-data; name="post[body]"
Content-Length: 8
postbody
-----------------------------7d226f700d0
content-disposition: form-data; name="post[assets_attributes][0][data]"; filename="C:/Users/mv288/files/1.txt"
content-type: application/octet-stream
ÿþ
sample file content
-----------------------------7d226f700d0
content-disposition: form-data; name="post[assets_attributes][0][data]"; filename="C:/Users/mv288/Pictures/1.txt"
content-type: application/octet-stream
ÿþ
sample file content
-----------------------------7d226f700d0

создается новое сообщение с двумя вложенными файлами.

теперь вопрос в том, что я хочу получить следующий HTTP-пост (обратите внимание на XML-часть перед вложениями файлов), чтобы также создать пост с 2-мя вложениями без дополнительных изменений (для posts_controller или rout.rb). это возможно?

POST /posts.xml HTTP/1.1
Content-type: multipart/mixed; boundary=---------------------------7d226f700d0
Accept: application/xml,text/html, image/gif, image/jpeg, *; q=.2, */*; q=.2
Cache-Control: no-cache
Pragma: no-cache
User-Agent: Java/1.6.0_21
Host: 192.168.0.105:8080
Connection: keep-alive
Content-Length: 1710

-----------------------------7d226f700d0
Content-type: application/xml; charset=UTF-8
Content-Length: 59
<post><body>postbody</body><title>post_title</title></post>
-----------------------------7d226f700d0
content-disposition: form-data; name="post[assets_attributes][0][data]"; filename="C:/Users/mv288/files/1.txt"
content-type: application/octet-stream
ÿþ
sample file content
-----------------------------7d226f700d0
content-disposition: form-data; name="post[assets_attributes][0][data]"; filename="C:/Users/mv288/Pictures/1.txt"
content-type: application/octet-stream
ÿþ
sample file content
-----------------------------7d226f700d0Blockquotetest

с использованием jruby 1.5.2 / jdk1.6, рельсов 2.3.4, paperclip-2.3.3 на Windows 2007 - 64 бит

1 Ответ

0 голосов
/ 08 октября 2010

По крайней мере, рельсы 2.3.4 не делают это автоматически. Нужно написать составной / связанный анализатор и зарегистрировать его внутри initializers / mime_types.rb

ПРИМЕЧАНИЕ. Не стесняйтесь обновлять жестко закодированные значения (например, основной и префикс вложенной части и т. Д.) В вашей копии.

Эту же стратегию можно использовать и для составного / связанного контента. Мы все еще обсуждаем, использовать ли multipart / related или multipart / mixed в этом примере ниже.

Примечания Microsoft по этому вопросу. http://msdn.microsoft.com/en-us/library/ms527355(EXCHG.10).aspx

Mime::Type.register "multipart/mixed", :mixed

class ActionController::Request
  def initialize(env)
    Thread.current[:request]=self
    super
  end

end

class MultiPartParamsParser

  def main_part_name
   "main"
  end

  def attachment_part_prefix
    "my_company_attachment"
  end

  def content_type(main_part)
    # TODO ----
    :xml_simple
  end

  def content(main_part)
    # TODO implement this
     if main_part.is_a?(String) 
       main_part.gsub!("Content-Type: application/xml",'') # remove content type if it exists
       main_part.strip! # to remove any trailing or leading whitespaces
     else
      main_part[:tempfile].read
     end
  end

  def request
    Thread.current[:request]
  end

  def parse_formatted_parameters(data)
    multi_parts = Rack::Utils::Multipart.parse_multipart(request.try(:env))
    main_part   = multi_parts[main_part_name]
    data        = content(main_part)
    # TODO return an error if data is not found
    params = case content_type(main_part)
      when :xml_simple, :xml_node
        data.blank? ? {} : Hash.from_xml(data).with_indifferent_access
      when :yaml
        YAML.load(data)
      when :json
        if data.blank?
          {}
        else
          ret = ActiveSupport::JSON.decode(data)
          ret = {:_json => data} unless data.is_a?(Hash)
          ret.with_indifferent_access
        end
      else
        {}
    end
    process_attachments(params, multi_parts)
    params                 
  end

  def process_attachments(data, multi_parts)
    data.each do |key, value|
      value ||= key # when array value is nil
      if value.is_a?(Hash) or value.is_a?(Array)
        process_attachments(value, multi_parts)
      elsif value.respond_to?(:match) and value.match("^#{attachment_part_prefix}") and (attachment=multi_parts[value]) # there could Time,Numbers etc.., but we match only string.
        data[key] = create_uploaded_file(attachment) # TODO handle the scenarios for short strings
      end 
    end         
  end

  def create_uploaded_file (attachment)
    upload = attachment[:tempfile]
    upload.extend(ActionController::UploadedFile)
    upload.original_path = attachment[:filename]
    upload.content_type = attachment[:type]
    upload
  end
end

proc = Proc.new do |data|
  MultiPartParamsParser.new.parse_formatted_parameters(data)
end

ActionController::Base.param_parsers[Mime::Type.lookup('multipart/mixed')] = proc

тогда вы можете опубликовать свое сообщение следующим образом. Вложение автоматически выполняется без каких-либо изменений моделей или контроллеров.

POST /posts.xml HTTP/1.1
Content-type: multipart/mixed; boundary=---------------------------###987612345###
Accept: application/xml,text/html, image/gif, image/jpeg, *; q=.2, */*; q=.2
Cache-Control: no-cache
Pragma: no-cache
Connection: keep-alive
Content-Length: ##

-----------------------------###987612345###
content-disposition: name="main"
Content-Length: ##
<post><title>post_title</title><body>post_body</body>
    <assets_attributes type="array">
            <asset><data>my_company_attachment_0</data> </asset>
            <asset><data>my_company_attachment_1</data> </asset>
    </assets_attributes>
</post>
-----------------------------###987612345###
content-disposition: name="my_company_attachment_0"; filename="C:/Users/mv288/files/1.txt"
content-type: application/octet-stream
ÿþ
sample file content
-----------------------------###987612345###
content-disposition: name="my_company_attachment_1"; filename="C:/Users/mv288/Pictures/1.png"
content-type: image/png
ÿþ
sample file content
-----------------------------###987612345###
...