Last active
July 11, 2022 15:07
-
-
Save stephendolan/35dc716f060729b866c4ed6b11722def to your computer and use it in GitHub Desktop.
Saving array of values to the DB in a Lucky operation
This file contains hidden or 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 Videos::FormFields < BaseComponent | |
needs operation : SaveVideo | |
div data_controller: "select" do | |
mount Shared::FieldLabel, operation.topic_ids, "Topics" | |
text_input operation.topic_ids, class: "hidden", data_select_target: "input" | |
tag "select", multiple: true, data_select_target: "select" do | |
render_topic_options | |
end | |
end | |
private def render_topic_options | |
existing_topics = if (persisted_record = operation.record) | |
persisted_record.topics | |
else | |
[] of Topic | |
end | |
TopicQuery.new.each do |topic| | |
attributes = existing_topics.includes?(topic) ? [:selected] : [] of Symbol | |
option topic.label, value: topic.id, attrs: attributes | |
end | |
end | |
end |
This file contains hidden or 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
# The operation to save a video | |
class SaveVideo < Video::SaveOperation | |
permit_columns title, description | |
attribute topic_ids : String | |
after_save associate_topics | |
private def associate_topics(video : Video) | |
return unless (topic_ids_string = topic_ids.value) | |
submitted_topics = topic_ids_string.split(",").map { |topic| UUID.new(topic) } | |
existing_topics = video.topics.map &.id | |
common_topics = existing_topics & submitted_topics | |
additional_topics = submitted_topics - existing_topics | |
# Remove topics that were not found in the submitted topics | |
VideoTopicQuery.new.video_id(video.id).topic_id.not.in(common_topics).delete | |
# Associate newly-added topics | |
additional_topics.each do |topic_id| | |
SaveVideoTopic.create!(video_id: video.id, topic_id: topic_id) | |
end | |
end | |
end |
This file contains hidden or 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
import { Controller } from "@hotwired/stimulus"; | |
import Choices from "choices.js"; | |
import "choices.js/public/assets/styles/choices.min.css"; | |
// Given some 'select' target, a Choices.js select will be created for it | |
// and values will be populated into the 'input' target's value field. | |
export default class extends Controller { | |
static targets = ["select", "input"]; | |
readonly selectTarget!: HTMLSelectElement; | |
readonly inputTarget!: HTMLInputElement; | |
connect(): void { | |
const choicesSelect = new Choices(this.selectTarget as HTMLSelectElement, { | |
allowHTML: false, | |
removeItemButton: true, | |
duplicateItemsAllowed: false, | |
}); | |
this.element.addEventListener("change", (event) => { | |
// We force this because the TypeScript definition doesn't account for the value-only Boolean paramter. | |
let currentValue = choicesSelect.getValue(true) as string | string[]; | |
if (!(currentValue instanceof Array)) { | |
currentValue = [currentValue]; | |
} | |
this.inputTarget.value = currentValue.join(","); | |
}); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment