Class: MontageRails::Base
- Inherits:
-
Object
- Object
- MontageRails::Base
- Extended by:
- ActiveModel::Callbacks, ActiveModel::Naming
- Includes:
- ActiveModel::Model
- Defined in:
- lib/montage_rails/base.rb,
lib/montage_rails/base/column.rb
Defined Under Namespace
Classes: Column
Instance Attribute Summary collapse
-
#persisted ⇒ Object
(also: #persisted?)
readonly
Returns the value of attribute persisted.
Class Method Summary collapse
-
.all ⇒ Object
Fetch all the documents.
- .attributes_from_response(response) ⇒ Object
-
.belongs_to(table) ⇒ Object
Define a belongs_to relationship.
-
.cache ⇒ Object
Define a new instance of the query cache.
-
.column_names ⇒ Object
Returns an array of the column names for the table.
-
.columns ⇒ Object
Returns an array of MontageRails::Base::Column’s for the schema.
-
.create(params = {}) ⇒ Object
Initialize and save a new instance of the object.
-
.find_by_id(value) ⇒ Object
(also: find)
Find a record by the id.
-
.find_or_initialize_by(params = {}) ⇒ Object
Find the record using the given params, or initialize a new one with those params.
-
.has_many(table, options = {}) ⇒ Object
Define a has_many relationship.
-
.inspect ⇒ Object
Returns a string like ‘Post id:integer, title:string, body:text’.
-
.logger ⇒ Object
Hook into the Rails logger.
- .method_missing(method_name, *args, &block) ⇒ Object
-
.relation ⇒ Object
Setup a class level instance of the MontageRails::Relation object.
- .respond_to_missing?(method_name, include_private = false) ⇒ Boolean
-
.set_table_name(value) ⇒ Object
(also: table_name=)
Redefine the table name.
-
.table_name ⇒ Object
The pluralized table name used in API requests.
Instance Method Summary collapse
-
#attribute_for_inspect(attr_name) ⇒ Object
Returns an
#inspect
-like string for the value of the attributeattr_name
. -
#attributes_valid? ⇒ Boolean
Performs a check to ensure that required columns have a value.
-
#column_for(name) ⇒ Object
Returns the Column class instance for the attribute passed in.
-
#destroy ⇒ Object
Destroy the copy of this record from the database.
-
#initialize(params = {}) ⇒ Base
constructor
A new instance of Base.
-
#inspect ⇒ Object
Returns the contents of the record as a nicely formatted string.
- #new_record? ⇒ Boolean
-
#payload ⇒ Object
Required for notifications to work, returns a payload suitable for the log subscriber.
-
#reload ⇒ Object
Reload the current document.
-
#save ⇒ Object
Save the record to the database.
-
#save! ⇒ Object
The bang method for save, which will raise an exception if saving is not successful.
-
#update_attributes(params) ⇒ Object
Update the given attributes for the document.
-
#updateable_attributes(include_id = false) ⇒ Object
The attributes used to update the document.
Constructor Details
#initialize(params = {}) ⇒ Base
Returns a new instance of Base.
212 213 214 215 216 217 218 |
# File 'lib/montage_rails/base.rb', line 212 def initialize(params = {}) initialize_columns @persisted = params[:persisted] ? params[:persisted] : false @current_method = "Load" @errors = ActiveModel::Errors.new(self) super(params) end |
Instance Attribute Details
#persisted ⇒ Object (readonly) Also known as: persisted?
Returns the value of attribute persisted.
205 206 207 |
# File 'lib/montage_rails/base.rb', line 205 def persisted @persisted end |
Class Method Details
.all ⇒ Object
Fetch all the documents
123 124 125 |
# File 'lib/montage_rails/base.rb', line 123 def all relation.to_a end |
.attributes_from_response(response) ⇒ Object
194 195 196 197 198 199 200 201 202 |
# File 'lib/montage_rails/base.rb', line 194 def attributes_from_response(response) case response.members when Montage::Documents then response.documents.first.attributes.merge(persisted: true) when Montage::Document then response.document.attributes.merge(persisted: true) when Montage::Errors then raise MontageAPIError, "There was an error with the Montage API: #{response.errors.attributes}" when Montage::Error then raise MontageAPIError, "There was an error with the Montage API: #{response.error.attributes}" else raise MontageAPIError, "There was an error with the Montage API, please try again." end end |
.belongs_to(table) ⇒ Object
Define a belongs_to relationship
66 67 68 69 70 71 72 73 74 75 76 77 |
# File 'lib/montage_rails/base.rb', line 66 def belongs_to(table) class_eval do define_method(table.to_s.tableize.singularize.to_sym) do table.to_s.classify.constantize.find_by_id(__send__(table.to_s.foreign_key)) end define_method("#{table.to_s.tableize.singularize}=") do |record| self.__send__("#{table.to_s.foreign_key}=", record.id) self end end end |
.cache ⇒ Object
Define a new instance of the query cache
29 30 31 |
# File 'lib/montage_rails/base.rb', line 29 def cache @cache ||= QueryCache.new(MontageRails.no_caching) end |
.column_names ⇒ Object
Returns an array of the column names for the table
159 160 161 |
# File 'lib/montage_rails/base.rb', line 159 def column_names columns.map { |c| c.name } end |
.columns ⇒ Object
Returns an array of MontageRails::Base::Column’s for the schema
99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 |
# File 'lib/montage_rails/base.rb', line 99 def columns @columns ||= [].tap do |ary| response = connection.schema(table_name) return [] unless response.schema.respond_to?(:fields) ary << Column.new("id", "text", false) ary << Column.new("created_at", "datetime", false) ary << Column.new("updated_at", "datetime", false) response.schema.fields.each do |field| ary << Column.new(field["name"], field["datatype"], field["required"]) instance_eval do define_singleton_method("find_by_#{field["name"]}") do |value| where("#{field["name"]} = '#{value}'").first end end end end end |
.create(params = {}) ⇒ Object
Initialize and save a new instance of the object
165 166 167 |
# File 'lib/montage_rails/base.rb', line 165 def create(params = {}) new(params).save end |
.find_by_id(value) ⇒ Object Also known as: find
Find a record by the id
129 130 131 132 133 134 135 136 137 |
# File 'lib/montage_rails/base.rb', line 129 def find_by_id(value) response = cache.get_or_set_query(self, value) { connection.document(table_name, value) } if response.success? new(response.document.items.merge(persisted: true)) else nil end end |
.find_or_initialize_by(params = {}) ⇒ Object
Find the record using the given params, or initialize a new one with those params
143 144 145 146 147 148 149 150 151 152 153 154 155 |
# File 'lib/montage_rails/base.rb', line 143 def find_or_initialize_by(params = {}) return nil if params.empty? query = relation.where(params) response = cache.get_or_set_query(self, query) { connection.documents(table_name, query) } if response.success? && response.documents.any? new(attributes_from_response(response).merge(persisted: true)) else new(params) end end |
.has_many(table, options = {}) ⇒ Object
Define a has_many relationship
47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 |
# File 'lib/montage_rails/base.rb', line 47 def has_many(table, = {}) class_eval do if [:as] define_method(table.to_s.tableize.to_sym) do table.to_s.classify.constantize.where( "#{[:as]}_id".to_sym => id, "#{[:as]}_type".to_sym => self.class.name.demodulize ) end else define_method(table.to_s.tableize.to_sym) do table.to_s.classify.constantize.where("#{self.class.table_name.demodulize.underscore.singularize.foreign_key} = #{id}") end end end end |
.inspect ⇒ Object
Returns a string like ‘Post id:integer, title:string, body:text’
171 172 173 174 175 176 177 178 |
# File 'lib/montage_rails/base.rb', line 171 def inspect if self == Base super else attr_list = columns.map { |c| "#{c.name}: #{c.type}" } * ', ' "#{super}(#{attr_list})" end end |
.logger ⇒ Object
Hook into the Rails logger
35 36 37 |
# File 'lib/montage_rails/base.rb', line 35 def logger @logger ||= Rails.logger end |
.method_missing(method_name, *args, &block) ⇒ Object
180 181 182 183 184 185 186 187 188 |
# File 'lib/montage_rails/base.rb', line 180 def method_missing(method_name, *args, &block) __send__(:columns) if respond_to?(method_name.to_sym) __send__(method_name.to_sym, *args) else super(method_name, *args, &block) end end |
.relation ⇒ Object
Setup a class level instance of the MontageRails::Relation object
41 42 43 |
# File 'lib/montage_rails/base.rb', line 41 def relation @relation = Relation.new(self) end |
.respond_to_missing?(method_name, include_private = false) ⇒ Boolean
190 191 192 |
# File 'lib/montage_rails/base.rb', line 190 def respond_to_missing?(method_name, include_private = false) __send__(:column_names).include?(method_name.to_s.split("_").first) || super(method_name, include_private) end |
.set_table_name(value) ⇒ Object Also known as: table_name=
Redefine the table name
87 88 89 90 91 92 93 |
# File 'lib/montage_rails/base.rb', line 87 def set_table_name(value) instance_eval do define_singleton_method(:table_name) do value end end end |
.table_name ⇒ Object
The pluralized table name used in API requests
81 82 83 |
# File 'lib/montage_rails/base.rb', line 81 def table_name self.name.demodulize.underscore.pluralize end |
Instance Method Details
#attribute_for_inspect(attr_name) ⇒ Object
Returns an #inspect
-like string for the value of the attribute attr_name
. String attributes are elided after 50 characters, and Date and Time attributes are returned in the :db
format. Other attributes return the value of #inspect
without modification.
person = Person.create!(:name => "David Heinemeier Hansson " * 3)
person.attribute_for_inspect(:name)
# => '"David Heinemeier Hansson David Heinemeier Hansson D..."'
person.attribute_for_inspect(:created_at)
# => '"2009-01-12 04:48:57"'
378 379 380 381 382 383 384 385 386 387 388 |
# File 'lib/montage_rails/base.rb', line 378 def attribute_for_inspect(attr_name) value = attributes[attr_name] if value.is_a?(String) && value.length > 50 "#{value[0..50]}...".inspect elsif value.is_a?(Date) || value.is_a?(Time) %("#{value.to_s(:db)}") else value.inspect end end |
#attributes_valid? ⇒ Boolean
Performs a check to ensure that required columns have a value
341 342 343 344 345 346 |
# File 'lib/montage_rails/base.rb', line 341 def attributes_valid? attributes.each do |key, value| next unless column_class = column_for(key.to_s) return false unless column_class.value_valid?(value) end end |
#column_for(name) ⇒ Object
Returns the Column class instance for the attribute passed in
335 336 337 |
# File 'lib/montage_rails/base.rb', line 335 def column_for(name) self.class.columns.select { |column| column.name == name }.first end |
#destroy ⇒ Object
Destroy the copy of this record from the database
307 308 309 310 311 312 313 |
# File 'lib/montage_rails/base.rb', line 307 def destroy @current_method = "Delete" notify(self) { connection.delete_document(self.class.table_name, id) } @persisted = false self end |
#inspect ⇒ Object
Returns the contents of the record as a nicely formatted string.
392 393 394 395 396 397 398 399 |
# File 'lib/montage_rails/base.rb', line 392 def inspect attributes_as_nice_string = self.class.column_names.collect { |name| if attributes[name.to_sym] || new_record? "#{name}: #{attribute_for_inspect(name.to_sym)}" end }.compact.join(", ") "#<#{self.class} #{attributes_as_nice_string}>" end |
#new_record? ⇒ Boolean
329 330 331 |
# File 'lib/montage_rails/base.rb', line 329 def new_record? !persisted? end |
#payload ⇒ Object
Required for notifications to work, returns a payload suitable for the log subscriber
357 358 359 360 361 362 |
# File 'lib/montage_rails/base.rb', line 357 def payload { reql: reql_payload[@current_method], name: "#{self.class.name} #{@current_method}" } end |
#reload ⇒ Object
Reload the current document
317 318 319 320 321 322 323 324 325 326 327 |
# File 'lib/montage_rails/base.rb', line 317 def reload @current_method = "Load" response = notify(self) do connection.document(self.class.table_name, id) end initialize(attributes_from_response(response)) @persisted = true self end |
#save ⇒ Object
Save the record to the database
Will return false if the attributes are not valid
Upon successful creation or update, will return true, otherwise returns false
226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 |
# File 'lib/montage_rails/base.rb', line 226 def save run_callbacks :save do return false unless valid? && attributes_valid? if persisted? @current_method = "Update" @response = notify(self) do connection.create_or_update_documents(self.class.table_name, [updateable_attributes(true)]) end initialize(attributes_from_response(@response)) else run_callbacks :create do @current_method = "Create" @response = notify(self) do connection.create_or_update_documents(self.class.table_name, [updateable_attributes(false)]) end if @response.success? @persisted = true initialize(attributes_from_response(@response)) else break end end end end @response.success? ? self : false end |
#save! ⇒ Object
The bang method for save, which will raise an exception if saving is not successful
261 262 263 264 265 266 267 268 269 |
# File 'lib/montage_rails/base.rb', line 261 def save! response = save unless response raise MontageAPIError, "There was an error saving your data" end response end |
#update_attributes(params) ⇒ Object
Update the given attributes for the document
Returns false if the given attributes aren’t valid
Returns a copy of self if updating is successful
277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 |
# File 'lib/montage_rails/base.rb', line 277 def update_attributes(params) old_attributes = attributes.clone params.each do |key, value| if respond_to?(key.to_sym) coerced_value = column_for(key.to_s).coerce(value) send("#{key}=", coerced_value) end end return self if old_attributes == attributes if valid? && attributes_valid? @current_method = id.nil? ? "Create" : "Update" response = notify(self) do connection.create_or_update_documents(self.class.table_name, [updateable_attributes(!id.nil?)]) end initialize(attributes_from_response(response)) @persisted = true self else initialize(old_attributes) false end end |
#updateable_attributes(include_id = false) ⇒ Object
The attributes used to update the document
350 351 352 |
# File 'lib/montage_rails/base.rb', line 350 def updateable_attributes(include_id = false) include_id ? attributes.except(:created_at, :updated_at) : attributes.except(:created_at, :updated_at, :id) end |