diff --git a/Gemfile b/Gemfile
index 47251781ebcca4f2a51a6ab023e1b24005ad0a4d..cfcb968b1c9b7c34a1f224931644c280ebe7a814 100644
--- a/Gemfile
+++ b/Gemfile
@@ -14,6 +14,9 @@ gem 'bcrypt', '~> 3.1.7'
 # memcached
 gem 'dalli'
 
+# dalli multi thread gem
+gem 'connection_pool'
+
 # web server
 gem 'puma'
 
diff --git a/app/controllers/concerns/downloadable_controller.rb b/app/controllers/concerns/downloadable_controller.rb
new file mode 100644
index 0000000000000000000000000000000000000000..4ab7cfae8ef2728001f78bb147057f308f9c92c8
--- /dev/null
+++ b/app/controllers/concerns/downloadable_controller.rb
@@ -0,0 +1,16 @@
+module DownloadableController
+  extend ActiveSupport::Concern
+
+  # GET /learning_objects/1/download
+  def download
+    downloadable.download(current_user, request.remote_ip)
+    redirect_to downloadable.download_link
+  end
+
+  protected
+
+  def downloadable
+    raise NotImplementedError
+  end
+
+end
diff --git a/app/controllers/v1/collections_controller.rb b/app/controllers/v1/collections_controller.rb
index b203f6b3164caa7a8eaf3a2cce6f8e2f6cb8c7e5..361c26be05f1eb69f8bfd43029d5479188bb049b 100644
--- a/app/controllers/v1/collections_controller.rb
+++ b/app/controllers/v1/collections_controller.rb
@@ -1,5 +1,6 @@
 class V1::CollectionsController < ApplicationController
   include ::SociableController
+  include ::DownloadableController
   include ::FollowableController
   include ::TaggableController
   include ::DeletedObjectsController
@@ -11,7 +12,7 @@ class V1::CollectionsController < ApplicationController
   before_action :authenticate_user!, only: [:create, :update, :destroy]
   before_action :set_collection, only: [:show, :update, :destroy, :add_object, :delete_object, :subjecting, :unsubjecting, :add_stages, :remove_stages]
   before_action :set_new_collection, only: :index
-  before_action :authorize!, except: [:create, :tagging, :untagging, :follow, :unfollow]
+  before_action :authorize!, except: [:create, :tagging, :untagging, :follow, :unfollow, :download]
 
   # GET /v1/collections
   # GET /v1/collections.json
@@ -83,6 +84,7 @@ class V1::CollectionsController < ApplicationController
   def followable; set_collection; end
   def taggable; set_collection; end
   def sociable; set_collection; end
+  def downloadable; set_collection; end
   def subjectable; set_collection; end
   def stageable; set_collection; end
 
diff --git a/app/controllers/v1/learning_objects_controller.rb b/app/controllers/v1/learning_objects_controller.rb
index 459ec9a07c4263cf215418ec326424d989b2b2a7..31fcba21dc35e7c653b058e5968b27686f280a96 100644
--- a/app/controllers/v1/learning_objects_controller.rb
+++ b/app/controllers/v1/learning_objects_controller.rb
@@ -2,6 +2,7 @@ require 'uri'
 
 class V1::LearningObjectsController < ApplicationController
   include ::SociableController
+  include ::DownloadableController
   include ::TaggableController
   include ::Paginator
   include ::DeletedObjectsController
@@ -12,10 +13,9 @@ class V1::LearningObjectsController < ApplicationController
   before_action :authenticate_user!, only: [:create, :update, :destroy]
   before_action :set_learning_object, only: [:show, :update, :destroy, :subjecting, :unsubjecting, :add_stages, :remove_stages]
   before_action :set_new_learning_object, only: :index
-  before_action :authorize!, except: [:create, :tagging, :untagging]
+  before_action :authorize!, except: [:create, :tagging, :untagging, :download]
   before_action :set_paper_trail_whodunnit
 
-
   def index
     learning_objects = paginate LearningObject.includes(:tags, :publisher, :language, :license, :subjects, :educational_stages, :reviews)
     serializer = params[:obaa].nil? ? LearningObjectSerializer : LearningObjectObaaSerializer
@@ -72,6 +72,7 @@ class V1::LearningObjectsController < ApplicationController
   def deleted_resource; LearningObject; end
   def highlights_resource; LearningObject; end
   def sociable; set_learning_object; end
+  def downloadable; set_learning_object; end
   def taggable; set_learning_object; end
   def subjectable; set_learning_object; end
   def stageable; set_learning_object; end
diff --git a/app/models/collection.rb b/app/models/collection.rb
index f3b7f2745949ffd7685e585600c73272172b3165..9f42147f89f82c1e02f0dad4ef9f56f38c7a59fa 100644
--- a/app/models/collection.rb
+++ b/app/models/collection.rb
@@ -25,6 +25,7 @@
 class Collection < ApplicationRecord
   include Reviewable
   include Sociable
+  include Downloadable
   include Followable
   include Scoreable
   include Thumbnailable
@@ -101,4 +102,8 @@ class Collection < ApplicationRecord
   def user_category
     owner.try('user_category')
   end
+
+  def download_link
+    '/'+PackageService.link(self)
+  end
 end
diff --git a/app/models/concerns/downloadable.rb b/app/models/concerns/downloadable.rb
new file mode 100644
index 0000000000000000000000000000000000000000..b813ac8371334bafc5a3394cc4cf020be5a17cda
--- /dev/null
+++ b/app/models/concerns/downloadable.rb
@@ -0,0 +1,21 @@
+module Downloadable
+  extend ActiveSupport::Concern
+
+  included do
+    has_many :downloads, as: :downloadable, dependent: :destroy
+    has_many :package_items, as: :packageable, dependent: :destroy
+    has_many :packages, through: :package_items, dependent: :destroy
+  end
+
+  def download(user, ip)
+    Download.where(user: user, ip: ip, downloadable: self).first_or_create
+  end
+
+  def downloaded?(user, ip)
+    !Download.where(user: user, ip: ip, downloadable: self).blank?
+  end
+
+  def download_link
+    raise NotImplementedError
+  end
+end
diff --git a/app/models/concerns/sociable.rb b/app/models/concerns/sociable.rb
index b3bf6ab3a954dc09bfb98784e35d25d668dd5cfd..2bc9fcb05f5896e3a1b7e2162afe4a1f52434f2f 100644
--- a/app/models/concerns/sociable.rb
+++ b/app/models/concerns/sociable.rb
@@ -3,7 +3,6 @@ module Sociable
 
   included do
     has_many :views, as: :viewable, dependent: :destroy
-    has_many :downloads, as: :downloadable, dependent: :destroy
     has_many :likes, as: :likeable, dependent: :destroy
     has_many :shares, as: :shareable, dependent: :destroy
   end
@@ -20,14 +19,6 @@ module Sociable
     Like.where(user: user, likeable: self).destroy_all
   end
 
-  def download(user)
-    Download.create(user: user, downloadable: self)
-  end
-
-  def downloaded?(user)
-    !Download.where(user: user, downloadable: self).blank?
-  end
-
   def share(user)
     Share.create(user: user, shareable: self)
   end
diff --git a/app/models/download.rb b/app/models/download.rb
index abebce69951491c8e64051b7841f3bd7995eda59..9812839a856ffcc25eebdacee249a507b5166125 100644
--- a/app/models/download.rb
+++ b/app/models/download.rb
@@ -8,16 +8,16 @@
 #  user_id           :integer
 #  created_at        :datetime         not null
 #  updated_at        :datetime         not null
-#
+#  ip                :string           not null
 
 class Download < ApplicationRecord
   # *current_user* download *downloadable*
   include Trackable
 
   belongs_to :downloadable, polymorphic: true, counter_cache: true
-  belongs_to :user
+  belongs_to :user, optional: true
 
-  validates_presence_of :user, :downloadable
+  validates_presence_of :ip, :downloadable
 
   def recipient
     downloadable
diff --git a/app/models/learning_object.rb b/app/models/learning_object.rb
index d47b733e0e2c92e8453294fdb55f361c41644ac8..fca93372bb6018ca9f4f50cae448bec9bd0dfc5d 100644
--- a/app/models/learning_object.rb
+++ b/app/models/learning_object.rb
@@ -34,6 +34,7 @@ class LearningObject < ApplicationRecord
   include Metadatable
   include Reviewable
   include Sociable
+  include Downloadable
   include Stateful
   include Scoreable
   include Thumbnailable
@@ -124,6 +125,10 @@ class LearningObject < ApplicationRecord
     default_attachment.retrieve_cache_link
   end
 
+  def download_link
+    object_type.try(:name) == ("Vídeo" || "Áudio") ? default_attachment.try(:retrieve_cache_link) : default_attachment.try(:retrieve_url)
+  end
+
   ## score methods
   def normalized_collected
     max = CollectionItem.where(collectionable_type: 'LearningObject').group(:collectionable_id).order('count_all DESC').count
diff --git a/app/models/package.rb b/app/models/package.rb
new file mode 100644
index 0000000000000000000000000000000000000000..3586b50125a959a323b808a365deadf194e1ba14
--- /dev/null
+++ b/app/models/package.rb
@@ -0,0 +1,20 @@
+# == Schema Information
+#
+# Table name: packages
+#
+# package_items_id      integer
+# created_at            datetime       null: false
+# updated_at            datetime       null: false
+# file_path             string
+
+class Package < ApplicationRecord
+  has_many :package_items, dependent: :destroy
+
+  validates_presence_of :file_path
+
+  def add_items(items)
+    items.each do |item|
+      package_item = PackageItem.where(package: self, packageable: item).first_or_create
+    end
+  end
+end
diff --git a/app/models/package_item.rb b/app/models/package_item.rb
new file mode 100644
index 0000000000000000000000000000000000000000..30952f09b528b0ffc10c1709ff381d0cf9a773aa
--- /dev/null
+++ b/app/models/package_item.rb
@@ -0,0 +1,16 @@
+# == Schema Information
+#
+# Table name: package_items
+#
+# package_id            integer
+# packageable_type      string
+# packageable_id        integer
+# created_at            datetime       null: false
+# updated_at            datetime       null: false
+
+class PackageItem < ApplicationRecord
+  belongs_to :package
+  belongs_to :packageable, polymorphic: true
+
+  validates :package, :packageable, presence: true
+end
diff --git a/app/serializers/learning_object_serializer.rb b/app/serializers/learning_object_serializer.rb
index 131f2278481ab30987cfcbac083e4c64c1e93a11..b1cdec145a3a0d84a079128a47c852b616e526e3 100644
--- a/app/serializers/learning_object_serializer.rb
+++ b/app/serializers/learning_object_serializer.rb
@@ -1,10 +1,6 @@
 class LearningObjectSerializer < ActiveModel::Serializer
   cache key: 'learning_object', expires_in: 4.hours, except: [:likes_count, :liked, :reviewed, :complained]
 
-  def default_location
-    object_type == ("Vídeo" || "Áudio") ? object.default_attachment.try(:retrieve_cache_link) : object.default_attachment.try(:retrieve_url)
-  end
-
   def default_mime_type
     object.default_attachment.try(:mime_type)
   end
@@ -42,7 +38,6 @@ class LearningObjectSerializer < ActiveModel::Serializer
              :object_type,
              :language,
              :default_attachment_id,
-             :default_location,
              :default_mime_type,
              :score,
              :state,
diff --git a/app/services/package_service.rb b/app/services/package_service.rb
index 945b4aaf27a8d05aec89b9d109763d6989baaff1..12928d0ad0c1b7bc1f6a38506de0c25de22247c3 100644
--- a/app/services/package_service.rb
+++ b/app/services/package_service.rb
@@ -8,7 +8,7 @@ module PackageService
   end
 
   def self.dirname
-    'download'
+    'packages'
   end
 
   def self.job_key(key)
diff --git a/app/services/package_service/generator.rb b/app/services/package_service/generator.rb
index ded3003f5f14968f4454c4bdb5e8ec840790f61c..330bc58c7abcc50429c8f747f9fbef69c738694e 100644
--- a/app/services/package_service/generator.rb
+++ b/app/services/package_service/generator.rb
@@ -1,27 +1,25 @@
 module PackageService
   class Generator
+
+    attr_reader :objects
+
     def initialize(objects)
       @objects = objects.is_a?(Array) ? objects : [objects]
-      @cache_key = nil
+      @filename = nil
 
       raise 'Invalid objects for PackageService' unless valid?
     end
 
     def generate
-      Rails.cache.write(PackageService.job_key(cache_key), 'wait')
-      PackageWorker.perform_async(objects_map, filename, cache_key)
+      PackageWorker.perform_async(objects_map, filename)
     end
 
-    def cache_key
-      return @cache_key unless @cache_key.nil?
-
-      key_name = 'package_service'
-      cache_list = []
-
-      @objects.sort_by!(&:id)
-      @objects.each { |o| cache_list << o.cache_key }
-
-      @cache_key = "#{key_name}[#{cache_list.join(',')}]"
+    def filename
+      while @filename.nil? do
+        name = "#{SecureRandom.hex(12)}.zip"
+        @filename = name unless File.exist?(PackageService.file_root(name))
+      end
+      @filename
     end
 
     private
@@ -36,13 +34,6 @@ module PackageService
       true
     end
 
-    def filename
-      loop do
-        name = "#{SecureRandom.hex(12)}.zip"
-        return name unless File.exist?(PackageService.file_root(name))
-      end
-    end
-
     def objects_map
       @objects.map { |o| { class: o.class, id: o.id } }
     end
diff --git a/app/services/package_service/link.rb b/app/services/package_service/link.rb
index 897fdc5f8ddcda37b9186ef3c683bbd1d6da25e8..433aeab02c7cf7e81baecc7e54710959edac6ad9 100644
--- a/app/services/package_service/link.rb
+++ b/app/services/package_service/link.rb
@@ -1,39 +1,50 @@
 module PackageService
   class Link
-    def initialize(object)
-      @generator = Generator.new(object)
-      @cache_key = @generator.cache_key
+    def initialize(objects)
+      @generator = Generator.new(objects)
     end
 
     def link
-      link = retrieve_link
-
+      link = get_package_link
       if link.nil?
         @generator.generate
         link = retrieve_link
       end
-
-      "#{PackageService.dirname}/#{link}" unless link.nil?
+      link
     end
 
     private
 
+    def get_package_link
+      package = PackageItem.select("package_id").where(:packageable => @generator.objects).group("package_id")
+      return nil if package.blank?
+      link = Package.find(package.first.package_id).file_path
+      if !File.exist?(Rails.root.join('public',link))
+        Package.destroy(package.first.package_id)
+        return nil
+      end
+      link
+    end
+
     def retrieve_link
       if wait_job
-        filename = Rails.cache.fetch(@cache_key)
-        return filename if !filename.nil? && File.exist?(PackageService.file_root(filename))
+        filename = @generator.filename
 
-        Rails.cache.delete(@cache_key) if Rails.cache.exist?(@cache_key)
+        filepath = PackageService.dirname+'/'+filename
+        package = Package.create(file_path: filepath)
+        package.add_items(@generator.objects)
+        return package.file_path
       end
 
       nil
     end
 
     def wait_job
-      job_key = PackageService.job_key(@cache_key)
-      unless Rails.cache.fetch(job_key).nil?
+      unless File.exist?(PackageService.file_root(@generator.filename))
         Timeout.timeout(60) do
-          sleep(1.0) until Rails.cache.fetch(job_key).nil? && !Rails.cache.fetch(@cache_key).nil?
+          begin
+            sleep(1.0)
+          end until File.exist?(PackageService.file_root(@generator.filename))
         end
       end
       true
diff --git a/app/workers/package_worker.rb b/app/workers/package_worker.rb
index cfaa9712ba25cdc8ffdc46393ac79453bc5e6fe1..427166f4705152b8cbb99a5b9afc59ac56008300 100644
--- a/app/workers/package_worker.rb
+++ b/app/workers/package_worker.rb
@@ -1,35 +1,25 @@
+require_dependency 'dspace'
+require 'rails'
 class PackageWorker
   include Sidekiq::Worker
   require 'zip'
 
   sidekiq_options queue: :package_cache
 
-  def perform(objects_ids = nil, filename = nil, cache_key = nil)
-    return false if objects_ids.blank? || filename.blank? || cache_key.blank?
-    @cache_key = cache_key
+  def perform(objects_ids = nil, filename = nil)
+    return false if objects_ids.blank? || filename.blank?
+    Bundler.require(*Rails.groups)
 
-    return true if file_exist?(PackageService.file_root(filename))
-
-    Rails.cache.write(PackageService.job_key(cache_key), 'wait')
+    return true if File.exist?(PackageService.file_root(filename))
 
     files = open_files(objects_ids)
     create_package(filename, files)
   ensure
     close_files(files) unless files.nil?
-    job_key = PackageService.job_key(cache_key)
-    Rails.cache.delete(job_key) if Rails.cache.exist?(job_key)
   end
 
   private
 
-  def file_exist?(path)
-    if File.exist?(path)
-      cache_fetch(path.split('/').last)
-      return true
-    end
-    false
-  end
-
   def open_files(objects_ids)
     objects = objects_ids.map { |o| o['class'].constantize.find(o['id']) }
 
@@ -61,7 +51,6 @@ class PackageWorker
     Zip::File.open(PackageService.file_root(filename), Zip::File::CREATE) do |zipfile|
       files.each { |file| zipfile.add(File.basename(file.path), file.path) }
     end
-    cache_fetch(filename)
   rescue => e
     file = PackageService.file_root(filename)
     FileUtils.rm(file) if File.exist?(file)
@@ -69,7 +58,7 @@ class PackageWorker
   end
 
   def open_file(file_path)
-    path = Rails.root.join('public', file_path)
+    path = Rails.root.join("public" + file_path)
     return File.open(path) if File.exist? path
     open_dspace_file(file_path)
   end
@@ -91,13 +80,4 @@ class PackageWorker
       FileUtils.rm(path) if path =~ %r{^\/tmp\/.*} && File.exist?(path)
     end
   end
-
-  def cache_fetch(value)
-    filename = Rails.cache.fetch(@cache_key)
-    file = PackageService.file_root(filename) unless filename.nil?
-    FileUtils.rm(file) if !file.nil? && File.exist?(file)
-
-    Rails.cache.delete(@cache_key)
-    Rails.cache.write(@cache_key, value)
-  end
 end
diff --git a/config/environments/development.rb b/config/environments/development.rb
index 9724cd4866a8248ceb1b79d1ec045fd170079787..9a835b03ca5ee8d11c8df3056ae2650ebfcfca35 100644
--- a/config/environments/development.rb
+++ b/config/environments/development.rb
@@ -28,7 +28,8 @@ Rails.application.configure do
   if Rails.root.join('tmp/caching-dev.txt').exist?
     config.action_controller.perform_caching = true
 
-    config.cache_store = :memory_store
+    config.cache_store = :dalli_store, nil, { :namespace => 'portalmec', :expires_in => 1.day, :compress => true, :pool_size => 5 }
+
     config.public_file_server.headers = {
       'Cache-Control' => 'public, max-age=172800'
     }
@@ -51,6 +52,8 @@ Rails.application.configure do
 
   config.log_level = :debug
 
+  config.public_file_server.enabled = true
+
   # Raises error for missing translations
   # config.action_view.raise_on_missing_translations = true
 
diff --git a/config/routes.rb b/config/routes.rb
index bf6e24c69db14c16ee3a9580e62b5f469d4e1a3d..c314a4533c81a8bfed191612d32c3f98c73169e8 100644
--- a/config/routes.rb
+++ b/config/routes.rb
@@ -43,6 +43,12 @@ Rails.application.routes.draw do
     end
   end
 
+  concern :downloadable do
+    member do
+      get 'download', as: :download, action: :download
+    end
+  end
+
   concern :reviewable do
     resources :reviews, only: [:index, :create, :update, :destroy], concerns: :deletable do
       member do
@@ -110,14 +116,14 @@ Rails.application.routes.draw do
       end
     end
 
-    resources :collections, concerns: [:followable, :sociable, :reviewable, :taggable, :versionable, :deletable, :highlights, :subjectable, :stageable] do
+    resources :collections, concerns: [:followable, :sociable, :downloadable, :reviewable, :taggable, :versionable, :deletable, :highlights, :subjectable, :stageable] do
       member do
         post :items, to: 'collections#add_object'
         delete :items, to: 'collections#delete_object'
       end
     end
 
-    resources :learning_objects, concerns: [:sociable, :reviewable, :taggable, :versionable, :deletable, :highlights, :subjectable, :stageable] do
+    resources :learning_objects, concerns: [:sociable, :downloadable, :reviewable, :taggable, :versionable, :deletable, :highlights, :subjectable, :stageable] do
       member do
         resource :chunk, module: 'learning_objects', only: [:create, :show]
         resource :upload, module: 'learning_objects', only: :create
diff --git a/db/migrate/20170215113455_add_ip_to_downloads.rb b/db/migrate/20170215113455_add_ip_to_downloads.rb
new file mode 100644
index 0000000000000000000000000000000000000000..8433592385ec31fbdeee87ab2f444958d0bac58a
--- /dev/null
+++ b/db/migrate/20170215113455_add_ip_to_downloads.rb
@@ -0,0 +1,5 @@
+class AddIpToDownloads < ActiveRecord::Migration[5.0]
+  def change
+    add_column :downloads, :ip, :string, null: false
+  end
+end
diff --git a/db/migrate/20170215121042_add_index_to_downloads.rb b/db/migrate/20170215121042_add_index_to_downloads.rb
new file mode 100644
index 0000000000000000000000000000000000000000..62859d2889387624c75b65872e6a469743531f28
--- /dev/null
+++ b/db/migrate/20170215121042_add_index_to_downloads.rb
@@ -0,0 +1,5 @@
+class AddIndexToDownloads < ActiveRecord::Migration[5.0]
+  def change
+    add_index :downloads, [:user_id, :ip, :downloadable_type, :downloadable_id], unique: true, name: 'user_ip_and_downloadable'
+  end
+end
diff --git a/db/migrate/20170223132327_create_packages.rb b/db/migrate/20170223132327_create_packages.rb
new file mode 100644
index 0000000000000000000000000000000000000000..c2e22f4584b5e4b9fa51e545a59f11e7d4ef8b5f
--- /dev/null
+++ b/db/migrate/20170223132327_create_packages.rb
@@ -0,0 +1,9 @@
+class CreatePackages < ActiveRecord::Migration[5.0]
+  def change
+    create_table :packages do |t|
+      t.references :package_items, index: true
+
+      t.timestamps
+    end
+  end
+end
diff --git a/db/migrate/20170223132838_create_package_items.rb b/db/migrate/20170223132838_create_package_items.rb
new file mode 100644
index 0000000000000000000000000000000000000000..14352c19c28f655183b8f548227c2eb391af77d2
--- /dev/null
+++ b/db/migrate/20170223132838_create_package_items.rb
@@ -0,0 +1,10 @@
+class CreatePackageItems < ActiveRecord::Migration[5.0]
+  def change
+    create_table :package_items do |t|
+      t.references :package, foreign_key: true
+      t.references :packageable, polymorphic: true
+
+      t.timestamps
+    end
+  end
+end
diff --git a/db/migrate/20170224145548_add_filepath_to_package.rb b/db/migrate/20170224145548_add_filepath_to_package.rb
new file mode 100644
index 0000000000000000000000000000000000000000..4ebbf5091493393108594f9a9514897e76480f0f
--- /dev/null
+++ b/db/migrate/20170224145548_add_filepath_to_package.rb
@@ -0,0 +1,5 @@
+class AddFilepathToPackage < ActiveRecord::Migration[5.0]
+  def change
+    add_column :packages, :file_path, :string
+  end
+end