|
| 1 | +# Migration to reassign items with the term "After 1999" to a newly categorized term. |
| 2 | +class UpdateTermItemRelation < ActiveRecord::Migration[7.0] |
| 3 | + def up |
| 4 | + facet = Facet.find_by!(name: 'Decade') |
| 5 | + t_after_2019 = Term.find_by!(facet: facet, value: 'After 1999') |
| 6 | + |
| 7 | + new_terms = { |
| 8 | + (2000..2009) => Term.find_by!(facet: facet, value: '2000-2009'), |
| 9 | + (2010..2019) => Term.find_by!(facet: facet, value: '2010-2019'), |
| 10 | + (2020..) => Term.find_by!(facet: facet, value: 'After 2020') |
| 11 | + } |
| 12 | + |
| 13 | + invalid_items = [] |
| 14 | + |
| 15 | + t_after_2019.items.find_each do |item| |
| 16 | + year = integer_year(item.date) |
| 17 | + unless year |
| 18 | + invalid_items << { id: item.id, date: item.date } |
| 19 | + next |
| 20 | + end |
| 21 | + |
| 22 | + target_term = new_terms.find { |range, _| range.cover?(year) }&.last |
| 23 | + next unless target_term |
| 24 | + |
| 25 | + re_assign_term_to_item(item, t_after_2019, target_term) |
| 26 | + end |
| 27 | + |
| 28 | + if invalid_items.any? |
| 29 | + Rails.logger.warn("Skipped #{invalid_items.size} items due to invalid or missing dates. Example: #{invalid_items.first(5).map { |i| "ID #{i[:id]}: '#{i[:date]}'" }.join(', ')}") |
| 30 | + end |
| 31 | + end |
| 32 | + |
| 33 | + def down |
| 34 | + facet = Facet.find_by!(name: 'Decade') |
| 35 | + target_term = Term.find_by!(facet: facet, value: 'After 1999') |
| 36 | + revert_term_assignment(facet, '2000-2009', target_term) |
| 37 | + revert_term_assignment(facet, '2010-2019', target_term) |
| 38 | + revert_term_assignment(facet, 'After 2020', target_term) |
| 39 | + end |
| 40 | + |
| 41 | + private |
| 42 | + |
| 43 | + def integer_year(val) |
| 44 | + return nil if val.nil? |
| 45 | + |
| 46 | + # Try direct integer conversion |
| 47 | + year = nil |
| 48 | + begin |
| 49 | + year = Integer(val) |
| 50 | + rescue ArgumentError, TypeError |
| 51 | + # Try to extract year from common date formats (e.g., "YYYY-MM-DD", "YYYY/MM/DD") |
| 52 | + if val.is_a?(String) |
| 53 | + if val =~ /\A(\d{4})[-\/]/ |
| 54 | + year = $1.to_i |
| 55 | + end |
| 56 | + end |
| 57 | + end |
| 58 | + return year |
| 59 | + end |
| 60 | + |
| 61 | + # Reassigns an item from the origin term to the target term, and removes the origin term from the item. |
| 62 | + def re_assign_term_to_item(item, origin_term, target_term) |
| 63 | + item.terms << target_term |
| 64 | + item.terms.delete(origin_term) |
| 65 | + end |
| 66 | + |
| 67 | + # Rolls back term assignment from origin_term_value to target_term for all items. |
| 68 | + def revert_term_assignment(facet, origin_term_value, target_term) |
| 69 | + origin_term = Term.find_by!(facet: facet, value: origin_term_value) |
| 70 | + origin_term.items.find_each do |item| |
| 71 | + re_assign_term_to_item(item, origin_term, target_term) |
| 72 | + end |
| 73 | + end |
| 74 | +end |
0 commit comments