Last active
September 22, 2023 21:39
-
-
Save carlosramireziii/6d0ca6b414d8a6af08371c30ba4dedcd to your computer and use it in GitHub Desktop.
A validator and RSpec matcher for restricting an attachment’s content type using Active Storage
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
require "rspec/expectations" | |
RSpec::Matchers.define :allow_content_type do |*content_types| | |
match do |record| | |
matcher.matches?(record, content_types) | |
end | |
chain :for do |attr_name| | |
matcher.for(attr_name) | |
end | |
chain :with_message do |message| | |
matcher.with_message(message) | |
end | |
private | |
def matcher | |
@matcher ||= AllowContentTypeMatcher.new | |
end | |
class AllowContentTypeMatcher | |
def for(attr_name) | |
@attr_name = attr_name | |
end | |
def with_message(message) | |
@message = message | |
end | |
def matches?(record, content_types) | |
Array.wrap(content_types).all? do |content_type| | |
record.send(attr_name).attach attachment_for(content_type) | |
record.valid? | |
!record.errors[attr_name].include? message | |
end | |
end | |
private | |
attr_reader :attr_name | |
def attachment_for(content_type) | |
suffix = content_type.to_s.split("/").last | |
{ io: StringIO.new("Hello world!"), filename: "test.#{suffix}", content_type: content_type } | |
end | |
def message | |
@message || I18n.translate("activerecord.errors.messages.content_type") | |
end | |
end | |
end | |
RSpec::Matchers.alias_matcher :allow_content_types, :allow_content_type |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
class ContentTypeValidator < ActiveModel::EachValidator | |
def validate_each(record, attribute, value) | |
unless value.attached? && value.content_type.in?(content_types) | |
value.purge if record.new_record? # Only purge the offending blob if the record is new | |
record.errors.add(attribute, :content_type, options) | |
end | |
end | |
private | |
def content_types | |
options.fetch(:in) | |
end | |
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
en: | |
activerecord: | |
errors: | |
messages: | |
content_type: is not a valid file format |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
@thelucid Yes, I got a similar error with the @meara approach.
can't modify frozen attributes
- Were you able to fix it? I added the check back and it worked as well:@carlosramireziii Thank you, it works nicely.