Class: WikiPage::Meta

Inherits:
ApplicationRecord show all
Includes:
Gitlab::Utils::StrongMemoize
Defined in:
app/models/wiki_page/meta.rb

Constant Summary collapse

CanonicalSlugConflictError =
Class.new(ActiveRecord::RecordInvalid)
WikiPageInvalid =
Class.new(ArgumentError)

Class Method Summary collapse

Instance Method Summary collapse

Methods included from Gitlab::Utils::StrongMemoize

#clear_memoization, #strong_memoize, #strong_memoized?

Methods inherited from ApplicationRecord

at_most, id_in, id_not_in, iid_in, pluck_primary_key, primary_key_in, safe_ensure_unique, safe_find_or_create_by, safe_find_or_create_by!, underscore, without_order

Class Method Details

.find_by_canonical_slug(canonical_slug, project) ⇒ Object


59
60
61
62
63
64
65
66
67
68
69
70
# File 'app/models/wiki_page/meta.rb', line 59

def find_by_canonical_slug(canonical_slug, project)
  meta, conflict = with_canonical_slug(canonical_slug)
    .where(project_id: project.id)
    .limit(2)

  if conflict.present?
    meta.errors.add(:canonical_slug, 'Duplicate value found')
    raise CanonicalSlugConflictError.new(meta)
  end

  meta
end

.find_or_create(last_known_slug, wiki_page) ⇒ Object

Return the (updated) WikiPage::Meta record for a given wiki page

If none is found, then a new record is created, and its fields are set to reflect the wiki_page passed.

This method raises errors on validation issues.

Parameters:

  • last_known_slug (String)
  • wiki_page (WikiPage)

Raises:


37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
# File 'app/models/wiki_page/meta.rb', line 37

def find_or_create(last_known_slug, wiki_page)
  raise WikiPageInvalid unless wiki_page.valid?

  project = wiki_page.wiki.project
  known_slugs = [last_known_slug, wiki_page.slug].compact.uniq
  raise 'No slugs found! This should not be possible.' if known_slugs.empty?

  transaction do
    updates = wiki_page_updates(wiki_page)
    found = find_by_canonical_slug(known_slugs, project)
    meta = found || create!(updates.merge(project_id: project.id))

    meta.update_state(found.nil?, known_slugs, wiki_page, updates)

    # We don't need to run validations here, since find_by_canonical_slug
    # guarantees that there is no conflict in canonical_slug, and DB
    # constraints on title and project_id enforce our other invariants
    # This saves us a query.
    meta
  end
end

Instance Method Details

#canonical_slugObject


85
86
87
# File 'app/models/wiki_page/meta.rb', line 85

def canonical_slug
  strong_memoize(:canonical_slug) { slugs.canonical.first&.slug }
end

#canonical_slug=(slug) ⇒ Object


89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
# File 'app/models/wiki_page/meta.rb', line 89

def canonical_slug=(slug)
  return if @canonical_slug == slug

  if persisted?
    transaction do
      slugs.canonical.update_all(canonical: false)
      page_slug = slugs.create_with(canonical: true).find_or_create_by(slug: slug)
      page_slug.update_columns(canonical: true) unless page_slug.canonical?
    end
  else
    slugs.new(slug: slug, canonical: true)
  end

  @canonical_slug = slug
end

#update_state(created, known_slugs, wiki_page, updates) ⇒ Object


105
106
107
108
109
# File 'app/models/wiki_page/meta.rb', line 105

def update_state(created, known_slugs, wiki_page, updates)
  update_wiki_page_attributes(updates)
  insert_slugs(known_slugs, created, wiki_page.slug)
  self.canonical_slug = wiki_page.slug
end