Created
June 10, 2012 16:16
-
-
Save jystewart/2906430 to your computer and use it in GitHub Desktop.
Tag code cleanup sketches
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
# A class to filter input parameters coming from a form in rails | |
# and collate them into a form suitable for use with a taggable | |
# object. | |
# | |
# This will mutate the params hash it is given. | |
# | |
# This could be used in a controller to take input that represents | |
# tags under its various names and collapse them to hand to a domain | |
# model that only knows about tags/tag_ids. Used with a decorator | |
# such as https://gist.github.com/2906392 it could handle everything | |
# if we wanted to keep knowledge of section/audience/etc. outside of | |
# the domain objects. | |
class TagCollationService | |
attr_accessor :our_parameters | |
def initialize(params, key) | |
@our_parameters = params[key] | |
end | |
def consolidate_tag_params | |
general_tags = [] | |
special_tags = [] | |
our_parameters.each do |key, value| | |
if key.match(/_tags$/) | |
general_tags += our_parameters.delete(key) | |
elsif key.match(/primary_(.+?)_tag/) | |
special_tags += our_parameters.delete(key) | |
end | |
end | |
general_tags -= special_tags | |
special_tags + general_tags | |
end | |
def mutate_params | |
our_parameters[:tag_ids] = consolidate_tag_params | |
end | |
end | |
require 'minitest/autorun' | |
class TaggingTest < MiniTest::Unit::TestCase | |
def core_params | |
params = { | |
artefact: { | |
slug: 'a', | |
name: 'a', | |
kind: 'answer', | |
section_tags: ['crime/the-police', 'blah/blah-blah'], | |
primary_section_tag: ['crime/hospitals'] | |
} | |
} | |
end | |
def test_compiles_section_tags | |
ts = TagCollationService.new(core_params, :artefact) | |
ts.mutate_params | |
refute params[:artefact][:section_tags] | |
refute params[:artefact][:primary_section_tag] | |
assert params[:artefact][:tag_ids] = ['crime/hospitals', 'crime/the-police', 'blah/blah-blah'] | |
end | |
test "can set sections" do | |
a = Artefact.create!(slug => "a", name: "a", kind: "answer", need_id: 1, owning_app: 'x') | |
a.sections = ['crime', 'crime/the-police'] | |
a.primary_section = 'crime' | |
a.reconcile_tags | |
assert_equal ['crime', 'crime/the-police'], a.tag_ids, 'Mismatched tags' | |
assert_equal ['crime', 'crime/the-police'], a.sections, 'Mismatched sections' | |
assert_equal 'Crime', a.section | |
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
# An unfinished sketch of a module to add 'taggable' behaviour to | |
# an item in the gov.uk publishing domain model. It won't work as is | |
# but is intended to demonstrate one mechanism for representing | |
# tagging. | |
# | |
# This could work and is quite a rails-y way to do it, but it feels | |
# like it's perhaps doing too much work to tie together the domain | |
# model and its persistence and so it'd be worth exploring alternatives. | |
# | |
module Taggable | |
module ClassMethods | |
def stores_tags_for(*keys) | |
keys.map!(&:to_s) | |
keys.each { |k| | |
attr_accessor k | |
# define_method "#{k.singularize}=" do |values| | |
# # tag_ids.clear | |
# # tags.clear | |
# values.each do |value| | |
# tag_id, tag = Tag.id_and_entity(value) | |
# tag_ids.push(tag_id) unless tag_ids.include?(tag_id) | |
# tags.push(tag_id) unless tags.include?(tag) | |
# end | |
# end | |
# define_method "#{k.singularize}_ids" do | |
# tags.select { |t| t.tag_type == k.singularize }.collect(&:tag_id) | |
# end | |
# define_method k do | |
# tags.select { |t| t.tag_type == k.singularize } | |
# end | |
} | |
self.tag_keys = keys | |
end | |
def has_primary_tag_for(key) | |
raise "Only one primary tag type allowed" unless key.is_a?(Symbol) | |
method_name = "primary_#{key.to_s.singularize}" | |
attr_accessor method_name | |
# define_method "#{method_name}=" do |value| | |
# tag_id, tag = Tag.id_and_entity(value) | |
# tag_ids.delete(tag_id) | |
# tag_ids.unshift(tag_id) | |
# tags.delete(tag) | |
# tags.unshift(tag) | |
# end | |
# define_method method_name do | |
# __send__(key.to_s.pluralize).first | |
# end | |
end | |
end | |
def self.included(klass) | |
klass.extend ClassMethods | |
klass.field :tag_ids, type: Array, default: [] | |
klass.attr_protected :tags, :tag_ids | |
klass.cattr_accessor :tag_keys, :primary_tag_keys | |
klass.private :tags, :tag_ids | |
end | |
def reconcile_tags | |
general_tags = [] | |
special_tags = [] | |
self.class.tag_keys.each do |key| | |
general_tags += __send__(key).to_a | |
end | |
self.class.primary_tag_keys.each do |key| | |
special_tags << __send__("primary_#{key.to_s.singularize}") | |
end | |
# Don't duplicate tags | |
general_tags -= special_tags | |
# Fill up tag_ids | |
self.tag_ids = (special_tags + general_tags).reject { |t| t.blank? } | |
end | |
# TODO: Work out best way to memoise this | |
def tags | |
TagRepository.load_all_with_ids(tag_ids).to_a | |
end | |
def save | |
reconcile_tags | |
parent | |
end | |
end |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment