Add validation to check translations amount on updates
In order to not allow users to remove all persited translations from any resource. A few exceptions were added: * Does not apply to globalizable models without translatable attributes required * Make a copy of main model error on current translations to be more realistic
This commit is contained in:
@@ -1,4 +1,5 @@
|
|||||||
module Globalizable
|
module Globalizable
|
||||||
|
MIN_TRANSLATIONS = 1
|
||||||
extend ActiveSupport::Concern
|
extend ActiveSupport::Concern
|
||||||
|
|
||||||
included do
|
included do
|
||||||
@@ -8,11 +9,18 @@ module Globalizable
|
|||||||
def locales_not_marked_for_destruction
|
def locales_not_marked_for_destruction
|
||||||
translations.reject(&:_destroy).map(&:locale)
|
translations.reject(&:_destroy).map(&:locale)
|
||||||
end
|
end
|
||||||
|
validate :check_translations_number, on: :update, if: :translations_required?
|
||||||
|
after_validation :copy_error_to_current_translation, on: :update
|
||||||
|
|
||||||
def description
|
def description
|
||||||
self.read_attribute(:description).try :html_safe
|
self.read_attribute(:description).try :html_safe
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
|
def translations_required?
|
||||||
|
translated_attribute_names.any?{|attr| required_attribute?(attr)}
|
||||||
|
end
|
||||||
|
|
||||||
if self.paranoid? && translation_class.attribute_names.include?("hidden_at")
|
if self.paranoid? && translation_class.attribute_names.include?("hidden_at")
|
||||||
translation_class.send :acts_as_paranoid, column: :hidden_at
|
translation_class.send :acts_as_paranoid, column: :hidden_at
|
||||||
end
|
end
|
||||||
@@ -21,6 +29,38 @@ module Globalizable
|
|||||||
|
|
||||||
private
|
private
|
||||||
|
|
||||||
|
def required_attribute?(attribute)
|
||||||
|
presence_validators = [ActiveModel::Validations::PresenceValidator,
|
||||||
|
ActiveRecord::Validations::PresenceValidator]
|
||||||
|
|
||||||
|
attribute_validators(attribute).any?{|validator| presence_validators.include? validator }
|
||||||
|
end
|
||||||
|
|
||||||
|
def attribute_validators(attribute)
|
||||||
|
self.class.validators_on(attribute).map(&:class)
|
||||||
|
end
|
||||||
|
|
||||||
|
def check_translations_number
|
||||||
|
errors.add(:base, :translations_too_short) unless traslations_count_valid?
|
||||||
|
end
|
||||||
|
|
||||||
|
def traslations_count_valid?
|
||||||
|
translations.reject(&:marked_for_destruction?).count >= MIN_TRANSLATIONS
|
||||||
|
end
|
||||||
|
|
||||||
|
def copy_error_to_current_translation
|
||||||
|
return unless errors.added?(:base, :translations_too_short)
|
||||||
|
|
||||||
|
if locales_persisted_and_marked_for_destruction.include?(I18n.locale)
|
||||||
|
locale = I18n.locale
|
||||||
|
else
|
||||||
|
locale = locales_persisted_and_marked_for_destruction.first
|
||||||
|
end
|
||||||
|
|
||||||
|
translation = translation_for(locale)
|
||||||
|
translation.errors.add(:base, :translations_too_short)
|
||||||
|
end
|
||||||
|
|
||||||
def searchable_globalized_values
|
def searchable_globalized_values
|
||||||
values = {}
|
values = {}
|
||||||
translations.each do |translation|
|
translations.each do |translation|
|
||||||
|
|||||||
@@ -448,6 +448,7 @@ en:
|
|||||||
valuation:
|
valuation:
|
||||||
cannot_comment_valuation: "You cannot comment a valuation"
|
cannot_comment_valuation: "You cannot comment a valuation"
|
||||||
messages:
|
messages:
|
||||||
|
translations_too_short: Is mandatory to provide one translation at least
|
||||||
record_invalid: "Validation failed: %{errors}"
|
record_invalid: "Validation failed: %{errors}"
|
||||||
another_poll_active: There is another poll active for the given period
|
another_poll_active: There is another poll active for the given period
|
||||||
restrict_dependent_destroy:
|
restrict_dependent_destroy:
|
||||||
|
|||||||
@@ -450,6 +450,7 @@ es:
|
|||||||
valuation:
|
valuation:
|
||||||
cannot_comment_valuation: "No puedes comentar una evaluación"
|
cannot_comment_valuation: "No puedes comentar una evaluación"
|
||||||
messages:
|
messages:
|
||||||
|
translations_too_short: El obligatorio proporcionar una traducción como mínimo
|
||||||
record_invalid: "Error de validación: %{errors}"
|
record_invalid: "Error de validación: %{errors}"
|
||||||
another_poll_active: Hay otra encuesta activa para este periodo.
|
another_poll_active: Hay otra encuesta activa para este periodo.
|
||||||
restrict_dependent_destroy:
|
restrict_dependent_destroy:
|
||||||
|
|||||||
@@ -236,6 +236,19 @@ shared_examples "edit_translatable" do |factory_name, path_name, input_fields, t
|
|||||||
expect_not_to_have_language "Español"
|
expect_not_to_have_language "Español"
|
||||||
end
|
end
|
||||||
|
|
||||||
|
scenario "Remove all translations should show an error message", :js do
|
||||||
|
skip("can't have invalid translations") if required_fields.empty?
|
||||||
|
|
||||||
|
visit path
|
||||||
|
|
||||||
|
click_link "Remove language"
|
||||||
|
click_link "Remove language"
|
||||||
|
|
||||||
|
click_button update_button_text
|
||||||
|
|
||||||
|
expect(page).to have_content "Is mandatory to provide one translation at least"
|
||||||
|
end
|
||||||
|
|
||||||
scenario "Remove a translation with invalid data", :js do
|
scenario "Remove a translation with invalid data", :js do
|
||||||
skip("can't have invalid translations") if required_fields.empty?
|
skip("can't have invalid translations") if required_fields.empty?
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user