Save selected tags to the display ad model (#18633)
* feat: Add a pack file that pulls in the MultiSelect Component * feat: move the tags to its own component * save tags * refactor: create a getCSRFToken function in the packs files so that it can be used in the admin * feat: import the new module in request.js * feat: remove unnecessary id * feat: first pass of csrf token test * chore: update the test * fix: csrf token * feat: hide the enw functionality behinda feature flag * fix: loading form twice * refactor: import for csrftoken * chore: update the description of the function * feat: use acts_on_taggable to craete a relationship between display_ad and tag * feat: add a tag field to the display_ad form * feat: add the selected tags from the multiselect autocomplete component to the input text field that references the tag_list * feat: add the tag_list to the controller so that we can save it to the db with the display ad parameters * feat: pull out the tag validation from the article and the display_ads into a concern * feat: write soem tests for validating the tag on the display_ads model * feat: add the tag_list as a hidden field * feat: set the selected tags on edit
This commit is contained in:
parent
c23b269410
commit
cae4c929ec
9 changed files with 89 additions and 10 deletions
|
|
@ -58,7 +58,8 @@ module Admin
|
|||
private
|
||||
|
||||
def display_ad_params
|
||||
params.permit(:organization_id, :body_markdown, :placement_area, :published, :approved, :name, :display_to)
|
||||
params.permit(:organization_id, :body_markdown, :placement_area, :published, :approved, :name, :display_to,
|
||||
:tag_list)
|
||||
end
|
||||
|
||||
def authorize_admin
|
||||
|
|
|
|||
|
|
@ -8,7 +8,7 @@ import { TagAutocompleteSelection } from '@crayons/MultiSelectAutocomplete/TagAu
|
|||
import { MultiSelectAutocomplete } from '@crayons';
|
||||
|
||||
/**
|
||||
* Tags for the article form. Allows users to search and select up to 4 tags.
|
||||
* Tags for the display ads admin form. Allows users to search and select up to 10 tags.
|
||||
*
|
||||
* @param {Function} onInput Callback to sync selections to article form state
|
||||
* @param {string} defaultValue Comma separated list of any currently selected tags
|
||||
|
|
|
|||
|
|
@ -9,15 +9,29 @@ Document.prototype.ready = new Promise((resolve) => {
|
|||
return null;
|
||||
});
|
||||
|
||||
function saveTags() {}
|
||||
function saveTags(selectionString) {
|
||||
document.getElementsByClassName('js-tags-textfield')[0].value =
|
||||
selectionString;
|
||||
}
|
||||
|
||||
function loadTagsField() {
|
||||
let defaultValue = '';
|
||||
const hiddenTagsField =
|
||||
document.getElementsByClassName('js-tags-textfield')[0];
|
||||
|
||||
if (hiddenTagsField) {
|
||||
defaultValue = hiddenTagsField.value.replaceAll(' ', ', ');
|
||||
}
|
||||
|
||||
const displayAdsTargetedTags = document.getElementById(
|
||||
'display-ad-targeted-tags',
|
||||
);
|
||||
|
||||
if (displayAdsTargetedTags) {
|
||||
render(<Tags onInput={saveTags} />, displayAdsTargetedTags);
|
||||
render(
|
||||
<Tags onInput={saveTags} defaultValue={defaultValue} />,
|
||||
displayAdsTargetedTags,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@ class Article < ApplicationRecord
|
|||
include CloudinaryHelper
|
||||
include ActionView::Helpers
|
||||
include Reactable
|
||||
include TagListValidateable
|
||||
include UserSubscriptionSourceable
|
||||
include PgSearch::Model
|
||||
|
||||
|
|
@ -768,12 +769,7 @@ class Article < ApplicationRecord
|
|||
# check there are not too many tags
|
||||
return errors.add(:tag_list, I18n.t("models.article.too_many_tags")) if tag_list.size > MAX_TAG_LIST_SIZE
|
||||
|
||||
# check tags names aren't too long and don't contain non alphabet characters
|
||||
tag_list.each do |tag|
|
||||
new_tag = Tag.new(name: tag)
|
||||
new_tag.validate_name
|
||||
new_tag.errors.messages[:name].each { |message| errors.add(:tag, "\"#{tag}\" #{message}") }
|
||||
end
|
||||
validate_tag_name(tag_list)
|
||||
end
|
||||
|
||||
def remove_tag_adjustments_from_tag_list
|
||||
|
|
|
|||
11
app/models/concerns/tag_list_validateable.rb
Normal file
11
app/models/concerns/tag_list_validateable.rb
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
module TagListValidateable
|
||||
extend ActiveSupport::Concern
|
||||
# we check tags names aren't too long and don't contain non alphabet characters
|
||||
def validate_tag_name(tag_list)
|
||||
tag_list.each do |tag|
|
||||
new_tag = Tag.new(name: tag)
|
||||
new_tag.validate_name
|
||||
new_tag.errors.messages[:name].each { |message| errors.add(:tag, "\"#{tag}\" #{message}") }
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
@ -1,4 +1,6 @@
|
|||
class DisplayAd < ApplicationRecord
|
||||
include TagListValidateable
|
||||
acts_as_taggable_on :tags
|
||||
resourcify
|
||||
|
||||
ALLOWED_PLACEMENT_AREAS = %w[sidebar_left sidebar_left_2 sidebar_right post_comments].freeze
|
||||
|
|
@ -7,6 +9,7 @@ class DisplayAd < ApplicationRecord
|
|||
"Sidebar Right",
|
||||
"Below the comment section"].freeze
|
||||
|
||||
MAX_TAG_LIST_SIZE = 10
|
||||
POST_WIDTH = 775
|
||||
SIDEBAR_WIDTH = 350
|
||||
|
||||
|
|
@ -18,6 +21,7 @@ class DisplayAd < ApplicationRecord
|
|||
validates :placement_area, presence: true,
|
||||
inclusion: { in: ALLOWED_PLACEMENT_AREAS }
|
||||
validates :body_markdown, presence: true
|
||||
validate :validate_tag
|
||||
before_save :process_markdown
|
||||
after_save :generate_display_ad_name
|
||||
|
||||
|
|
@ -50,6 +54,13 @@ class DisplayAd < ApplicationRecord
|
|||
ALLOWED_PLACEMENT_AREAS_HUMAN_READABLE[ALLOWED_PLACEMENT_AREAS.find_index(placement_area)]
|
||||
end
|
||||
|
||||
def validate_tag
|
||||
# check there are not too many tags
|
||||
return errors.add(:tag_list, I18n.t("models.article.too_many_tags")) if tag_list.size > MAX_TAG_LIST_SIZE
|
||||
|
||||
validate_tag_name(tag_list)
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def generate_display_ad_name
|
||||
|
|
|
|||
|
|
@ -37,6 +37,7 @@ class Tag < ActsAsTaggableOn::Tag
|
|||
belongs_to :badge, optional: true
|
||||
|
||||
has_many :articles, through: :taggings, source: :taggable, source_type: "Article"
|
||||
has_many :display_ads, through: :taggings, source: :taggable, source_type: "DisplayAd"
|
||||
|
||||
mount_uploader :profile_image, ProfileImageUploader
|
||||
mount_uploader :social_image, ProfileImageUploader
|
||||
|
|
|
|||
|
|
@ -24,6 +24,11 @@
|
|||
<div class="crayons-field">
|
||||
<div id="display-ad-targeted-tags"></div>
|
||||
</div>
|
||||
|
||||
<div class="crayons-field hidden">
|
||||
<%= label_tag :tag_list, "tag_list:", class: "crayons-field__label" %>
|
||||
<%= text_field_tag :tag_list, @display_ad.tag_list, class: "crayons-textfield js-tags-textfield" %>
|
||||
</div>
|
||||
<% end %>
|
||||
|
||||
<div class="crayons-field">
|
||||
|
|
|
|||
|
|
@ -137,4 +137,44 @@ RSpec.describe DisplayAd, type: :model do
|
|||
expect(described_class.search_ads("foo")).to eq([])
|
||||
end
|
||||
end
|
||||
|
||||
describe ".validate_tag" do
|
||||
it "rejects more than 10 tags" do
|
||||
eleven_tags = "one, two, three, four, five, six, seven, eight, nine, ten, eleven"
|
||||
expect(build(:display_ad,
|
||||
name: "This is an Ad",
|
||||
body_markdown: "Ad Body",
|
||||
placement_area: "post_comments",
|
||||
tag_list: eleven_tags).valid?).to be(false)
|
||||
end
|
||||
|
||||
it "rejects tags with length > 30" do
|
||||
tags = "'testing tag length with more than 30 chars', tag"
|
||||
expect(build(:display_ad,
|
||||
name: "This is an Ad",
|
||||
body_markdown: "Ad Body",
|
||||
placement_area: "post_comments",
|
||||
tag_list: tags).valid?).to be(false)
|
||||
end
|
||||
|
||||
it "rejects tag with non-alphanumerics" do
|
||||
expect do
|
||||
build(:display_ad,
|
||||
name: "This is an Ad",
|
||||
body_markdown: "Ad Body",
|
||||
placement_area: "post_comments",
|
||||
tag_list: "c++").validate!
|
||||
end.to raise_error(ActiveRecord::RecordInvalid)
|
||||
end
|
||||
|
||||
it "always downcase tags" do
|
||||
tags = "UPPERCASE, CAPITALIZE"
|
||||
display_ad = create(:display_ad,
|
||||
name: "This is an Ad",
|
||||
body_markdown: "Ad Body",
|
||||
placement_area: "post_comments",
|
||||
tag_list: tags)
|
||||
expect(display_ad.tag_list).to eq(tags.downcase.split(", "))
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue