Class: Simplec::Page
- Inherits:
-
ApplicationRecord
- Object
- ActiveRecord::Base
- ApplicationRecord
- Simplec::Page
- Defined in:
- app/models/simplec/page.rb
Overview
This class represents a page in the system.
Model and Template Relationship.
This is a para with code. WTF
Each page has:
-
a class located in:
app/models/page/NAME.rb -
a partial template in:
app/views/pages/_NAME.html.erb
Where NAME is the demodulized, snake-case name of the Page Subclass.
Direct Known Subclasses
Defined Under Namespace
Classes: AlreadyLinkedEmbeddedImage
Constant Summary collapse
- FILE_FIELDS =
[:file, :image].freeze
Instance Attribute Summary collapse
-
#fields ⇒ JSON
JSONB Postgres field that holds all defined fields.
-
#layout ⇒ String
This is the layout to be used when the page is rendered.
-
#meta_description ⇒ String
This is the meta description tag for the page.
-
#path ⇒ String
readonly
The the path is computed from the slug and the sum all parent pages.
-
#slug ⇒ String
The value is normalized to a string starting without a leading slash and ending without a slash.
-
#title ⇒ String
This is the title of the page.
Class Method Summary collapse
-
.field(name, options = {}) ⇒ Object
Define a field on the page.
-
.field_names(type = nil) ⇒ Object
Return names of fields.
- .fields ⇒ Hash
-
.index! ⇒ NilClass
Index every record.
-
.search(term, options = {}) ⇒ ActiveRecord::Relation
If the term is nil or blank, all results will be returned.
-
.search_query_attributes ⇒ Array
Get extra attributes on the record for querying.
-
.search_query_attributes!(*args) ⇒ Object
Set extra attributes on the record for querying.
-
.tsquery(input, options = {}) ⇒ String
Create a to_tsquery statement.
-
.type(type) ⇒ Class
Return a constantized type, whitelisted by known subclasses.
Instance Method Summary collapse
-
#build_path ⇒ String
Build the path of the page to be used in routing.
-
#extract_search_text(*attributes) ⇒ String
Extract text out of HTML or plain strings.
-
#field_options ⇒ Object
Return field options for building forms.
-
#find_embedded_images ⇒ Array
Search all of the fields text and create an array of all found Simplec::EmbeddedImages.
-
#index! ⇒ Boolean
Index this record for search.
-
#layouts ⇒ Array
Get layout options.
-
#link_embedded_images! ⇒ Array
Set this instance as the #embeddable association on the Simplec::EmbeddedImage.
-
#match_parent_subdomain ⇒ Simplec::Subdomain
Sets the #subdomain t that of the parent.
-
#parents ⇒ Object
List parents, closest to furthest.
-
#set_query_attributes! ⇒ Hash
Build query attribute hash.
-
#set_search_text! ⇒ Object
Set the text which will be index.
Instance Attribute Details
#fields ⇒ JSON
JSONB Postgres field that holds all defined fields. Use only if you know what you are doing.
|
|
# File 'app/models/simplec/page.rb', line 85
|
#layout ⇒ String
This is the layout to be used when the page is rendered. This attribute overrides the associated Subdomain’s default_layout.
See Simplec::Subdomain#layouts to get a list of optional layouts.
|
|
# File 'app/models/simplec/page.rb', line 77
|
#meta_description ⇒ String
This is the meta description tag for the page.
|
|
# File 'app/models/simplec/page.rb', line 73
|
#path ⇒ String (readonly)
The the path is computed from the slug and the sum all parent pages.
|
|
# File 'app/models/simplec/page.rb', line 65
|
#slug ⇒ String
The value is normalized to a string starting without a leading slash and ending without a slash. Case is not changed.
|
|
# File 'app/models/simplec/page.rb', line 60
|
#title ⇒ String
This is the title of the page.
|
|
# File 'app/models/simplec/page.rb', line 69
|
Class Method Details
.field(name, options = {}) ⇒ Object
Define a field on the page
There is as template for each type for customization located in:
app/views/shared/fields/_TYPE.html.erb
Defines a field on a subclass. This creates a getter and setter for the name passed in. The options are used when building the administration forms.
Regular dragonfly validations are available on :file and :image fields. markevans.github.io/dragonfly/models#validations
:string - yields a text input
:text - yields a textarea
:editor - yields a summernote editor
:file - yields a file field
:image - yields a file field with image preview
143 144 145 146 147 148 149 150 151 152 |
# File 'app/models/simplec/page.rb', line 143 def self.field(name, ={}) fields[name] = {name: name, type: :string}.merge() if FILE_FIELDS.member?(fields[name][:type]) dragonfly_accessor name data_field :"#{name}_uid" data_field :"#{name}_name" else data_field(name) end end |
.field_names(type = nil) ⇒ Object
Return names of fields.
type: :file, is the only option
174 175 176 177 178 179 180 181 182 183 184 |
# File 'app/models/simplec/page.rb', line 174 def self.field_names(type=nil) _fields = case type when :file fields.select {|k, v| FILE_FIELDS.member?(v[:type])} when :textual fields.select {|k, v| !FILE_FIELDS.member?(v[:type])} else fields end _fields.keys end |
.fields ⇒ Hash
155 156 157 |
# File 'app/models/simplec/page.rb', line 155 def self.fields @fields ||= Hash.new end |
.index! ⇒ NilClass
Index every record.
Internally this method iterates over all pages in batches of 3.
227 228 229 |
# File 'app/models/simplec/page.rb', line 227 def self.index! find_each(batch_size: 3) { |page| page.index! } end |
.search(term, options = {}) ⇒ ActiveRecord::Relation
If the term is nil or blank, all results will be returned.
106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 |
# File 'app/models/simplec/page.rb', line 106 scope :search, ->(term, ={}) { _types = Array(.delete(:types)) _subdomains = Array(.delete(:subdomains)) query = all query = query.includes(:subdomain). where(simplec_subdomains: {name: _subdomains}) if _subdomains.any? query = query.where(type: _types) if _types.any? .each { |k,v| query = query.where("query->>:k = :v", k: k, v: v) } if term.blank? query else tsq = tsquery term query.where("tsv @@ #{tsq}").order("ts_rank_cd(tsv, #{tsq}) DESC") end } |
.search_query_attributes ⇒ Array
Get extra attributes on the record for querying.
See #search_query_attributes! for more information.
218 219 220 |
# File 'app/models/simplec/page.rb', line 218 def self.search_query_attributes @_search_query_attrs = Set.new(@_search_query_attrs).add(:id).to_a end |
.search_query_attributes!(*args) ⇒ Object
Set extra attributes on the record for querying.
209 210 211 |
# File 'app/models/simplec/page.rb', line 209 def self.search_query_attributes!(*args) @_search_query_attrs = args.map(&:to_sym) end |
.tsquery(input, options = {}) ⇒ String
Create a to_tsquery statement.
Mainly used internally, but could be used in custom queries.
242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 |
# File 'app/models/simplec/page.rb', line 242 def self.tsquery(input, ={}) [:language] ||= 'english' value = input.to_s.strip value = value. gsub('(', ''). gsub(')', ''). gsub(%q('), ''). gsub(' ', '\\ '). gsub(':', ''). gsub("\t", ''). gsub("!", '') value << ':*' query = "to_tsquery(?, ?)" sanitize_sql_array([query, [:language], value]) end |
.type(type) ⇒ Class
Return a constantized type, whitelisted by known subclasses.
163 164 165 166 167 168 |
# File 'app/models/simplec/page.rb', line 163 def self.type(type) ::Page rescue raise '::Page not defined, define it in app/models' raise 'Unsupported Page Type; define in app/models/page/' unless ::Page.subclasses.map(&:name). member?(type) type.constantize end |
Instance Method Details
#build_path ⇒ String
Build the path of the page to be used in routing.
Used as a before validation hook.
282 283 284 285 |
# File 'app/models/simplec/page.rb', line 282 def build_path _pages = self.parents.reverse + [self] self.path = _pages.map(&:slug).reject(&:blank?).join('/') end |
#extract_search_text(*attributes) ⇒ String
Extract text out of HTML or plain strings. Basically removes html formatting.
355 356 357 358 359 360 |
# File 'app/models/simplec/page.rb', line 355 def extract_search_text(*attributes) Array(attributes).map { |meth| Nokogiri::HTML(self.send(meth)).xpath("//text()"). map {|node| text = node.text; text.try(:strip!); text}.join(" ") }.reject(&:blank?).join("\n") end |
#field_options ⇒ Object
Return field options for building forms.
260 261 262 |
# File 'app/models/simplec/page.rb', line 260 def self.class.fields.values end |
#find_embedded_images ⇒ Array
Search all of the fields text and create an array of all found Simplec::EmbeddedImages.
304 305 306 307 308 309 310 |
# File 'app/models/simplec/page.rb', line 304 def text = self.fields.values.join(' ') matches = text.scan(/ei=([^&]*)/) encoded_ids = matches.map(&:first) ids = encoded_ids.map { |eid| Base64.urlsafe_decode64(URI.unescape(eid)) } EmbeddedImage.includes(:embeddable).find(ids) end |
#index! ⇒ Boolean
Index this record for search.
Internally, this method uses update_columns so it can be used in after_save callbacks, etc.
342 343 344 345 346 |
# File 'app/models/simplec/page.rb', line 342 def index! set_search_text! set_query_attributes! update_columns text: self.text, query: self.query end |
#layouts ⇒ Array
Get layout options.
See Simplec::Subdomain#layouts.
332 333 334 |
# File 'app/models/simplec/page.rb', line 332 def layouts @layouts ||= Subdomain.new.layouts end |
#link_embedded_images! ⇒ Array
Set this instance as the #embeddable association on the
Simplec::EmbeddedImage
Used as an after_save hook.
318 319 320 321 322 323 324 325 |
# File 'app/models/simplec/page.rb', line 318 def images = self. images.each do |image| raise AlreadyLinkedEmbeddedImage if image. && image. != self image.update!(embeddable: self) end end |
#match_parent_subdomain ⇒ Simplec::Subdomain
Sets the #subdomain t that of the parent.
All pages need to have a matching subdomain to parent page. Does nothing if there is no parent.
Used as a before validation hook.
295 296 297 298 |
# File 'app/models/simplec/page.rb', line 295 def match_parent_subdomain return unless self.parent self.subdomain = self.parent.subdomain end |
#parents ⇒ Object
List parents, closest to furthest.
This is a recursive, expensive call.
268 269 270 271 272 273 274 275 |
# File 'app/models/simplec/page.rb', line 268 def parents page, parents = self, Array.new while page.parent page = page.parent parents << page end parents end |
#set_query_attributes! ⇒ Hash
Build query attribute hash.
Internally stored as JSONB.
384 385 386 387 388 389 390 |
# File 'app/models/simplec/page.rb', line 384 def set_query_attributes! attr_names = self.class.search_query_attributes.map(&:to_s) self.query = attr_names.inject({}) { |memo, attr| memo[attr] = self.send(attr) memo } end |
#set_search_text! ⇒ Object
Set the text which will be index.
a title, meta_description b slug, path (non-printable, add tags, added terms) c textual fields d (reserved for sub-records, etc)
‘a’ correlates to ‘A’ priority in Postgresql. For more information: www.postgresql.org/docs/9.6/static/functions-textsearch.html
372 373 374 375 376 377 |
# File 'app/models/simplec/page.rb', line 372 def set_search_text! self.text['a'] = extract_search_text :title, :meta_description self.text['b'] = extract_search_text :slug, :path self.text['c'] = extract_search_text *self.class.field_names(:textual) self.text['d'] = nil end |