Class: SourceMonitor::Source
- Inherits:
-
ApplicationRecord
- Object
- ActiveRecord::Base
- ApplicationRecord
- SourceMonitor::Source
- 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
-
.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.
-
.enable_scraping!(ids) ⇒ Object
Bulk-enable scraping for sources that don’t already have it enabled.
- .ransackable_associations(_auth_object = nil) ⇒ Object
- .ransackable_attributes(_auth_object = nil) ⇒ Object
- .scrape_candidates(threshold: SourceMonitor.config.scraping.scrape_recommendation_threshold) ⇒ Object
Instance Method Summary collapse
- #auto_paused? ⇒ Boolean
- #avg_word_count ⇒ Object
- #clear_favicon_cooldown! ⇒ Object
- #fetch_circuit_open? ⇒ Boolean
- #fetch_interval_hours ⇒ Object
- #fetch_interval_hours=(value) ⇒ Object
- #fetch_interval_minutes=(value) ⇒ Object
- #fetch_retry_attempt ⇒ Object
- #reset_items_counter! ⇒ Object
Methods included from Models::UrlNormalizable
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
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_count ⇒ Object
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
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_hours ⇒ Object
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_attempt ⇒ Object
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 |