RailsでファイルをDLさせたい

Railsでxmlやらjsonやらをアクセスされたら出力内容をそのまんまファイル保存してもらいたかったり
なんならZIPしてDLさせたかったりする(xmlではないかな)場合こうかな?と書いてみた。

viewファイルでなんとかする場合

xml

index.rss.jbuilder
xml.instruct! :xml, :version => "1.0" 
xml.rss("version" => "2.0", "xmlns:dc" => "http://purl.org/dc/elements/1.1/") do
  xml.channel do
    xml.title "title"
 
    @articles.each do |article|
      xml.item do
        xml.title article.title
        xml.description strip_tags(article.content.gsub(/[\r\n]/,"")).truncate(400)
        xml.pubDate article.created_at.to_s(:rfc822)
        xml.guid "http://aaa.aa/article/#{article.id}"
        xml.link "http://aaa.aa/article/#{article.id}"
      end
    end
  end
end

json

index.json.jbuilder
json.array!(@articles) do |article|
    json.id article.id
    json.title article.title
    json.content article.content
end

出力→DL

def dl
    @articles = Article.all()
    respond_to do |format|
        # json
        format.json do
            send_data render_to_string, filename: "articles.json", type: :json
        end
        # xml
        format.rss do
            send_data render_to_string, filename: "articles.xml", type: :xml 
        end
    end
end

出力→zip→DL

def zip_dl
    require 'rubygems'
    require 'zip'
    require 'tmpdir'

    tmpdir = Dir.mktmpdir
    filename = 'data.zip'

    begin
        Zip::File.open("#{tmpdir}/#{filename}", Zip::File::CREATE) do |zip|
            @articles = Article.all()
            zip.get_output_stream("articles.xml") do |fp|
                fp.puts render_to_string(:template => "articles/index.rss.builder", :layout => false)
            end
            zip.get_output_stream("articles.json") do |fp|
                fp.puts render_to_string(:template => "articles/index.json.builder", :layout => false)
            end
        end
        zip_data = File.read("#{tmpdir}/#{filename}")
        send_data(zip_data, :type => 'application/zip', :filename => filename)
    ensure
        FileUtils.remove_entry_secure tmpdir
    end

modelでなんとかする場合

各フォーマットへの変換関数を利用

article.rb

def self.get_json()
        json = Article.all()
        # belongs_toのアイテムなどをアレしてもいい
        return json.to_json
end
def self.get_xml()
        json = Article.all()
        # belongs_toのアイテムなどをアレしてもいい
        return json.to_xml
end

zip→DL

def zip_dl
    require 'rubygems'
    require 'zip'
    require 'tmpdir'

    tmpdir = Dir.mktmpdir
    filename = 'data.zip'

    begin
        Zip::File.open("#{tmpdir}/#{filename}", Zip::File::CREATE) do |zip|
            zip.get_output_stream("articles.json") do |fp|
                fp.puts Article.get_json()
            end
        end
        Zip::File.open("#{tmpdir}/#{filename}", Zip::File::CREATE) do |zip|
            zip.get_output_stream("articles.xml") do |fp|
                fp.puts Article.get_xml()
            end
        end
        zip_data = File.read("#{tmpdir}/#{filename}")
        send_data(zip_data, :type => 'application/zip', :filename => filename)
    ensure
        FileUtils.remove_entry_secure tmpdir
    end
end

もっといい書き方ないかなー?