Class: SourceMonitor::Source

Inherits:
ApplicationRecord show all
Includes:
Models::Sanitizable, Models::UrlNormalizable
Defined in:
app/models/source_monitor/source.rb

Constant Summary collapse

FETCH_STATUS_VALUES =
%w[idle queued fetching failed].freeze
HEALTH_STATUS_VALUES =
%w[working declining improving failing].freeze

Class Method Summary collapse

Instance Method Summary collapse

Methods included from Models::UrlNormalizable

#url_invalid?

Class Method Details

.due_for_fetch(reference_time: Time.current) ⇒ Object

Convert scope to class method to make reference_time parameter explicit Scopes with internal variables should be class methods per Rails best practices



64
65
66
# File 'app/models/source_monitor/source.rb', line 64

def due_for_fetch(reference_time: Time.current)
  active.where(arel_table[:next_fetch_at].eq(nil).or(arel_table[:next_fetch_at].lteq(reference_time)))
end

.enable_scraping!(ids) ⇒ Object

Bulk-enable scraping for sources that don’t already have it enabled. Returns the number of records updated.



74
75
76
77
78
79
80
81
82
83
# File 'app/models/source_monitor/source.rb', line 74

def enable_scraping!(ids)
  default_adapter = column_defaults["scraper_adapter"] || "readability"

  where(id: ids, scraping_enabled: false).update_all(
    scraping_enabled: true,
    auto_scrape: true,
    scraper_adapter: default_adapter,
    updated_at: Time.current
  )
end

.ransackable_associations(_auth_object = nil) ⇒ Object



91
92
93
# File 'app/models/source_monitor/source.rb', line 91

def ransackable_associations(_auth_object = nil)
  []
end

.ransackable_attributes(_auth_object = nil) ⇒ Object



85
86
87
88
89
# File 'app/models/source_monitor/source.rb', line 85

def ransackable_attributes(_auth_object = nil)
  %w[name feed_url website_url created_at fetch_interval_minutes items_count last_fetched_at
     active health_status feed_format scraper_adapter scraping_enabled
     new_items_per_day avg_feed_words avg_scraped_words]
end

.scrape_candidates(threshold: SourceMonitor.config.scraping.scrape_recommendation_threshold) ⇒ Object



68
69
70
# File 'app/models/source_monitor/source.rb', line 68

def scrape_candidates(threshold: SourceMonitor.config.scraping.scrape_recommendation_threshold)
  SourceMonitor::Analytics::ScrapeRecommendations.new(threshold:).relation
end

Instance Method Details

#auto_paused?Boolean

Returns:

  • (Boolean)


145
146
147
# File 'app/models/source_monitor/source.rb', line 145

def auto_paused?
  auto_paused_until.present? && auto_paused_until.future?
end

#avg_word_countObject



161
162
163
164
165
166
# File 'app/models/source_monitor/source.rb', line 161

def avg_word_count
  items.joins(:item_content)
       .where.not(ItemContent.table_name => { scraped_word_count: nil })
       .average("#{ItemContent.table_name}.scraped_word_count")
       &.round
end

#clear_favicon_cooldown!Object



156
157
158
159
# File 'app/models/source_monitor/source.rb', line 156

def clear_favicon_cooldown!
   = ( || {}).except("favicon_last_attempted_at")
  update_column(:metadata, )
end

#fetch_circuit_open?Boolean

Returns:

  • (Boolean)


136
137
138
# File 'app/models/source_monitor/source.rb', line 136

def fetch_circuit_open?
  fetch_circuit_until.present? && fetch_circuit_until.future?
end

#fetch_interval_hoursObject



130
131
132
133
134
# File 'app/models/source_monitor/source.rb', line 130

def fetch_interval_hours
  return 0 unless fetch_interval_minutes

  fetch_interval_minutes.to_f / 60.0
end

#fetch_interval_hours=(value) ⇒ Object



126
127
128
# File 'app/models/source_monitor/source.rb', line 126

def fetch_interval_hours=(value)
  self.fetch_interval_minutes = (value.to_f * 60).round if value.present?
end

#fetch_interval_minutes=(value) ⇒ Object



122
123
124
# File 'app/models/source_monitor/source.rb', line 122

def fetch_interval_minutes=(value)
  self[:fetch_interval_minutes] = value.presence && value.to_i
end

#fetch_retry_attemptObject



140
141
142
143
# File 'app/models/source_monitor/source.rb', line 140

def fetch_retry_attempt
  value = super
  value.present? ? value : 0
end

#reset_items_counter!Object



149
150
151
152
153
154
# File 'app/models/source_monitor/source.rb', line 149

def reset_items_counter!
  # Recalculate items_count from actual active (non-deleted) items
  # Use reset_counters which is the Rails-native way to fix counter caches
  self.class.reset_counters(id, :items)
  reload
end