Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Started on ActiveStorage matchers #1194

Merged
merged 1 commit into from
Jul 24, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions lib/shoulda/matchers/active_record.rb
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
require "shoulda/matchers/active_record/define_enum_for_matcher"
require "shoulda/matchers/active_record/uniqueness"
require "shoulda/matchers/active_record/validate_uniqueness_of_matcher"
require "shoulda/matchers/active_record/have_attached_matcher"
StefSchenkelaars marked this conversation as resolved.
Show resolved Hide resolved

module Shoulda
module Matchers
Expand Down
147 changes: 147 additions & 0 deletions lib/shoulda/matchers/active_record/have_attached_matcher.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,147 @@
module Shoulda
module Matchers
module ActiveRecord
def have_one_attached(name)
HaveAttachedMatcher.new(:one, name)
end

def have_many_attached(name)
HaveAttachedMatcher.new(:many, name)
end

# @private
class HaveAttachedMatcher
attr_reader :name

def initialize(macro, name)
@macro = macro
@name = name
end

def description
"have a has_#{macro}_attached called #{name}"
end
StefSchenkelaars marked this conversation as resolved.
Show resolved Hide resolved

def failure_message
<<-MESSAGE
Expected #{expectation}, but this could not be proved.
#{@failure}
MESSAGE
end

def failure_message_when_negated
<<-MESSAGE
Did not expect #{expectation}, but it does.
MESSAGE
end

def expectation
"#{model_class.name} to #{description}"
end

def matches?(subject)
@subject = subject
reader_attribute_exists? &&
writer_attribute_exists? &&
attachments_association_exists? &&
blobs_association_exists? &&
eager_loading_scope_exists?
end

private

attr_reader :subject, :macro

def reader_attribute_exists?
if subject.respond_to?(name)
true
else
@failure = "#{model_class.name} does not have a :#{name} method."
false
end
end

def writer_attribute_exists?
if subject.respond_to?("#{name}=")
true
else
@failure = "#{model_class.name} does not have a :#{name}= method."
false
end
end

def attachments_association_exists?
StefSchenkelaars marked this conversation as resolved.
Show resolved Hide resolved
if attachments_association_matcher.matches?(subject)
true
else
@failure = attachments_association_matcher.failure_message
false
end
end

def attachments_association_matcher
@_attachments_association_matcher ||=
AssociationMatcher.new(
:"has_#{macro}",
attachments_association_name,
).
conditions(name: name).
class_name('ActiveStorage::Attachment').
inverse_of(:record)
end

def attachments_association_name
case macro
when :one then
"#{name}_attachment"
when :many then
"#{name}_attachments"
end
end

def blobs_association_exists?
if blobs_association_matcher.matches?(subject)
true
else
@failure = blobs_association_matcher.failure_message
false
end
end

def blobs_association_matcher
@_blobs_association_matcher ||=
AssociationMatcher.new(
:"has_#{macro}",
blobs_association_name,
).
through(attachments_association_name).
class_name('ActiveStorage::Blob').
source(:blob)
end

def blobs_association_name
case macro
when :one then
"#{name}_blob"
when :many then
"#{name}_blobs"
end
end

StefSchenkelaars marked this conversation as resolved.
Show resolved Hide resolved
def eager_loading_scope_exists?
StefSchenkelaars marked this conversation as resolved.
Show resolved Hide resolved
if model_class.respond_to?("with_attached_#{name}")
true
else
@failure = "#{model_class.name} does not have a " \
":with_attached_#{name} scope."
false
end
end

def model_class
subject.class
end
end
end
end
end
4 changes: 4 additions & 0 deletions spec/support/unit/helpers/active_record_versions.rb
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,10 @@ def active_record_supports_expression_indexes?
active_record_version >= 5
end

def active_record_supports_active_storage?
active_record_version >= 5.2
end

def active_record_supports_validate_presence_on_active_storage?
active_record_version >= '6.0.0.beta1'
end
Expand Down
4 changes: 4 additions & 0 deletions spec/support/unit/helpers/rails_versions.rb
Original file line number Diff line number Diff line change
Expand Up @@ -18,5 +18,9 @@ def rails_lt_5?
def rails_5_x?
rails_version =~ '~> 5.0'
end

def rails_gte_5_2?
StefSchenkelaars marked this conversation as resolved.
Show resolved Hide resolved
rails_version >= 5.2
end
end
end
Loading