Add arguments to documentable concern to make it configurable for any recipient model.

This commit is contained in:
Senén Rodero Rodríguez
2017-07-21 19:48:57 +02:00
parent 62372aaee3
commit 38d4d59241
11 changed files with 78 additions and 22 deletions

View File

@@ -7,13 +7,14 @@ class Budget
include Reclassification include Reclassification
include Followable include Followable
include Documentable include Documentable
documentable max_documents_allowed: 3,
max_file_size: 3.megabytes,
accepted_content_types: [ "application/pdf" ]
acts_as_votable acts_as_votable
acts_as_paranoid column: :hidden_at acts_as_paranoid column: :hidden_at
include ActsAsParanoidAliases include ActsAsParanoidAliases
MAX_DOCUMENTS_SIZE = 3
belongs_to :author, -> { with_hidden }, class_name: 'User', foreign_key: 'author_id' belongs_to :author, -> { with_hidden }, class_name: 'User', foreign_key: 'author_id'
belongs_to :heading belongs_to :heading
belongs_to :group belongs_to :group

View File

@@ -5,4 +5,16 @@ module Documentable
has_many :documents, as: :documentable, dependent: :destroy has_many :documents, as: :documentable, dependent: :destroy
end end
module ClassMethods
attr_reader :max_documents_allowed, :max_file_size, :accepted_content_types
private
def documentable(options= {})
@max_documents_allowed = options[:max_documents_allowed]
@max_file_size = options[:max_file_size]
@accepted_content_types = options[:accepted_content_types]
end
end
end end

View File

@@ -4,12 +4,36 @@ class Document < ActiveRecord::Base
belongs_to :user belongs_to :user
belongs_to :documentable, polymorphic: true belongs_to :documentable, polymorphic: true
validates_attachment :attachment, presence: true, validates_attachment :attachment, presence: true
content_type: { content_type: "application/pdf" }, do_not_validate_attachment_file_type :attachment
size: { in: 0..3.megabytes } validate :validate_attachment_content_type
validate :validate_attachment_size
validates :title, presence: true validates :title, presence: true
validates :user, presence: true validates :user, presence: true
validates :documentable_id, presence: true validates :documentable_id, presence: true
validates :documentable_type, presence: true validates :documentable_type, presence: true
def validate_attachment_size
if attachment.file? && documentable.present? && attachment_file_size > documentable.class.max_file_size
errors[:attachment] = I18n.t("documents.errors.messages.in_between",
min: "0 Bytes",
max: "#{bytesToMeg(documentable.class.max_file_size)} MB")
end
end
def validate_attachment_content_type
if attachment.file? && documentable.present? && !documentable.class.accepted_content_types.include?(attachment_content_type)
errors[:attachment] = I18n.t("documents.errors.messages.content_type",
content_type: attachment_content_type,
accepted_content_types: documentable.class.accepted_content_types.join(", "))
end
end
private
def bytesToMeg bytes
bytes / (1024.0 * 1024.0)
end
end end

View File

@@ -10,12 +10,14 @@ class Proposal < ActiveRecord::Base
include Graphqlable include Graphqlable
include Followable include Followable
include Documentable include Documentable
documentable max_documents_allowed: 3,
max_file_size: 3.megabytes,
accepted_content_types: [ "application/pdf" ]
acts_as_votable acts_as_votable
acts_as_paranoid column: :hidden_at acts_as_paranoid column: :hidden_at
include ActsAsParanoidAliases include ActsAsParanoidAliases
MAX_DOCUMENTS_SIZE = 3
RETIRE_OPTIONS = %w(duplicated started unfeasible done other) RETIRE_OPTIONS = %w(duplicated started unfeasible done other)
belongs_to :author, -> { with_hidden }, class_name: 'User', foreign_key: 'author_id' belongs_to :author, -> { with_hidden }, class_name: 'User', foreign_key: 'author_id'

View File

@@ -4,7 +4,7 @@
<div class="small-12 medium-9 column"> <div class="small-12 medium-9 column">
<%= back_link_to budget_investments_path(investment.budget, heading_id: investment.heading) %> <%= back_link_to budget_investments_path(investment.budget, heading_id: investment.heading) %>
<% if can?(:create, @document) && investment.documents.size < Budget::Investment::MAX_DOCUMENTS_SIZE %> <% if can?(:create, @document) && investment.documents.size < Budget::Investment.max_documents_allowed %>
<%= link_to t("documents.upload_document"), <%= link_to t("documents.upload_document"),
new_document_path(documentable_id:investment, documentable_type: investment.class.name, from: request.url), new_document_path(documentable_id:investment, documentable_type: investment.class.name, from: request.url),
class: 'button hollow float-right' %> class: 'button hollow float-right' %>

View File

@@ -23,7 +23,7 @@
<div class="tabs-panel" id="tab-documents"> <div class="tabs-panel" id="tab-documents">
<%= render 'documents/documents', <%= render 'documents/documents',
documents: @investment.documents, documents: @investment.documents,
max_documents_size: Budget::Investment::MAX_DOCUMENTS_SIZE %> max_documents_allowed: Budget::Investment.max_documents_allowed %>
</div> </div>
</div> </div>

View File

@@ -1,10 +1,10 @@
<% if documents.any? %> <% if documents.any? %>
<% if documents.size == max_documents_size %> <% if documents.size == max_documents_allowed %>
<div class="row documents-list"> <div class="row documents-list">
<div class="small-12 column"> <div class="small-12 column">
<div class="callout primary text-center"> <div class="callout primary text-center">
<%= t "documents.max_documents_size_reached" %> <%= t "documents.max_documents_allowed_reached" %>
</div> </div>
</div> </div>
</div> </div>

View File

@@ -16,7 +16,7 @@
<div class="small-12 medium-9 column"> <div class="small-12 medium-9 column">
<%= back_link_to %> <%= back_link_to %>
<% if can?(:create, @document) && @proposal.documents.size < Proposal::MAX_DOCUMENTS_SIZE %> <% if can?(:create, @document) && @proposal.documents.size < Proposal.max_documents_allowed %>
<%= link_to t("documents.upload_document"), <%= link_to t("documents.upload_document"),
new_document_path(documentable_id: @proposal, documentable_type: @proposal.class.name, from: request.url), new_document_path(documentable_id: @proposal, documentable_type: @proposal.class.name, from: request.url),
class: 'button hollow float-right' %> class: 'button hollow float-right' %>
@@ -166,6 +166,6 @@
<div class="tabs-panel" id="tab-documents"> <div class="tabs-panel" id="tab-documents">
<%= render 'documents/documents', <%= render 'documents/documents',
documents: @proposal.documents, documents: @proposal.documents,
max_documents_size: Proposal::MAX_DOCUMENTS_SIZE %> max_documents_allowed: Proposal.max_documents_allowed %>
</div> </div>
</div> </div>

View File

@@ -3,7 +3,7 @@ en:
tab: Documents tab: Documents
no_documents: Don't have uploaded documents no_documents: Don't have uploaded documents
upload_document: Upload document upload_document: Upload document
max_documents_size_reached: You have reached the maximum number of documents allowed! You have to delete one before you can upload another. max_documents_allowed_reached: You have reached the maximum number of documents allowed! You have to delete one before you can upload another.
form: form:
attachment_label: Choose attachment file attachment_label: Choose attachment file
submit_button: Upload document submit_button: Upload document
@@ -24,3 +24,7 @@ en:
download_document: Download PDF download_document: Download PDF
destroy_document: Destroy destroy_document: Destroy
link_document: Link link_document: Link
errors:
messages:
in_between: must be in between %{min} and %{max}
wrong_content_type: content type %{content_type} does not match any of accepted content types %{accepted_content_types}

View File

@@ -3,7 +3,7 @@ es:
tab: Documentos tab: Documentos
no_documents: No hay documentos subidos no_documents: No hay documentos subidos
upload_document: Subir documento upload_document: Subir documento
max_documents_size_reached: ¡Has alcanzado el número máximo de documentos permitidos! Tienes que eliminar uno antes de poder subir otro. max_documents_allowed_reached: ¡Has alcanzado el número máximo de documentos permitidos! Tienes que eliminar uno antes de poder subir otro.
form: form:
attachment_label: Selecciona un archivo attachment_label: Selecciona un archivo
submit_button: Subir documento submit_button: Subir documento
@@ -24,3 +24,7 @@ es:
download_document: Descargar PDF download_document: Descargar PDF
destroy_document: Eliminar destroy_document: Eliminar
link_document: Enlace link_document: Enlace
errors:
messages:
in_between: debe estar entre %{min} y %{max}
wrong_content_type: El tipo de contenido %{content_type} del archivo no coincide con ninguno de los tipos de contenido aceptados %{accepted_content_types}

View File

@@ -1,6 +1,8 @@
shared_examples "document validations" do |documentable_factory| shared_examples "document validations" do |documentable_factory|
let(:document) { build(:document, documentable_factory.to_sym) } let(:document) { build(:document, documentable_factory.to_sym) }
let(:max_file_size) { document.documentable.class.max_file_size }
let(:accepted_content_types) { document.documentable.class.accepted_content_types }
it "should be valid" do it "should be valid" do
expect(document).to be_valid expect(document).to be_valid
@@ -18,17 +20,20 @@ shared_examples "document validations" do |documentable_factory|
expect(document).to_not be_valid expect(document).to_not be_valid
end end
it "should not be valid for attachment images" do it "should be valid for all accepted content types" do
document.attachment = File.new("spec/fixtures/files/logo_header.png") accepted_content_types.each do |content_type|
extension = content_type.split("/").last
document.attachment = File.new("spec/fixtures/files/empty.#{extension}")
expect(document).to_not be_valid expect(document).to be_valid
end
end end
it "should not be valid for attachment 3MB" do it "should not be valid for attachments larger than documentable max_file_size definition" do
document.stub(:attachment_file_size).and_return(3.1.megabytes) document.stub(:attachment_file_size).and_return(max_file_size.bytes + 1.byte)
document.should_not be_valid expect(document).to_not be_valid
expect(document.errors[:attachment]).to include "must be in between 0 Bytes and 3 MB" expect(document.errors[:attachment]).to include "must be in between 0 Bytes and #{bytesToMeg(max_file_size)} MB"
end end
it "should not be valid without a user_id" do it "should not be valid without a user_id" do
@@ -50,3 +55,7 @@ shared_examples "document validations" do |documentable_factory|
end end
end end
def bytesToMeg(bytes)
bytes / (1024.0 * 1024.0)
end