Class: LazyRecord

Inherits:
Studio54::Base show all
Extended by:
ActiveModel::Callbacks, ActiveModel::Naming, ActiveModel::Translation
Includes:
ActiveModel::Serializers::JSON, ActiveModel::Serializers::Xml, ActiveModel::Validations, Studio54
Defined in:
lib/lazy_record.rb

Direct Known Subclasses

Post, User

Constant Summary collapse

RecordNotFound =
Class.new(StandardError)
AssociationNotFound =
Class.new(StandardError)

Class Method Summary collapse

Instance Method Summary collapse

Methods inherited from Studio54::Base

require_all_models, require_models

Constructor Details

#initialize(params = nil) ⇒ LazyRecord

if parameters are given, builds the model object with the attributes from the given parameters



24
25
26
27
28
29
# File 'lib/lazy_record.rb', line 24

def initialize(params=nil)
  unless params.nil?
    self.build_from_params!(params)
  end
  @errors = ActiveModel::Errors.new(self)
end

Class Method Details

.allObject



334
335
336
337
338
339
340
341
# File 'lib/lazy_record.rb', line 334

def self.all
  sql = "SELECT * FROM #{self.table_name}"
  res = nil
  db_try do
    res = Db.conn.execute(sql)
  end
  build_from res, :always_return_array => true
end

.all_attributesObject



43
44
45
46
47
48
# File 'lib/lazy_record.rb', line 43

def self.all_attributes
  @all_attributes ||= begin
    attrs = @attributes.dup
    attrs.unshift primary_key
  end
end

.attributesObject



39
40
41
# File 'lib/lazy_record.rb', line 39

def self.attributes
  @attributes ||= []
end

.belongs_to_attributesObject



54
55
56
# File 'lib/lazy_record.rb', line 54

def self.belongs_to_attributes
  @belongs_to_attributes ||= []
end

.db_tryObject



283
284
285
286
287
288
289
290
291
292
293
294
295
# File 'lib/lazy_record.rb', line 283

def self.db_try
  begin
    yield
  rescue DBI::DatabaseError
    @retries ||= 0; @retries += 1
    if @retries == 1
      load 'config/db_connect.rb'
      retry
    else
      raise
    end
  end
end

.find(id) ⇒ Object

id is the primary key of the table, and does not need to be named ‘id’ in the table itself TODO take into account other dbms’s, this only works w/ mysql



301
302
303
304
305
306
307
308
# File 'lib/lazy_record.rb', line 301

def self.find(id)
  sql = "SELECT * FROM #{self.table_name} WHERE #{self.primary_key} = ?"
  res = nil
  db_try do
    res = Db.conn.execute sql, id
  end
  build_from res
end

.find_by(hash, options = {}) ⇒ Object



310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
# File 'lib/lazy_record.rb', line 310

def self.find_by(hash, options={})
  opts = {:conjunction => 'AND'}.merge options
  conj = opts[:conjunction]
  sql = "SELECT * FROM #{self.table_name} WHERE "
  values = []
  hash.each do |k, v|
    sql += "#{k} = ? #{conj} "
    values << v
  end
  case conj
  when 'AND'
    sql = sql[0...-4]
  when 'OR'
    sql = sql[0...-3]
  else
    raise "conjunction in sql condition (WHERE) must be one of AND, OR"
  end
  res = nil
  db_try do
    res = Db.conn.execute sql, *values
  end
  build_from res
end

.inherited(base) ⇒ Object



14
15
16
17
18
19
# File 'lib/lazy_record.rb', line 14

def self.inherited(base)
  base.class_eval do
    cattr_accessor :primary_key
    attr_reader :errors
  end
end

.method_missing(method, *args, &block) ⇒ Object



371
372
373
374
375
376
377
378
379
380
381
382
# File 'lib/lazy_record.rb', line 371

def method_missing(method, *args, &block)
  if method =~ %r{find_by_(.*)}
    h_args = {$1 => args[0]}
    return __send__ :find_by, h_args, &block
  end

  if method =~ %r{table_name}
    return __send__ :assoc_table_name=
  end

  super
end

.nested_attributesObject



50
51
52
# File 'lib/lazy_record.rb', line 50

def self.nested_attributes
  @nested_attributes ||= []
end

.tbl_attr_accessor(*fields) ⇒ Object

used to keep track of all table attributes



32
33
34
35
36
37
# File 'lib/lazy_record.rb', line 32

def self.tbl_attr_accessor *fields
  fields.each do |f|
    self.attributes << f.to_s unless self.attributes.include? f.to_s
  end
  self.__send__ :attr_accessor, *fields
end

Instance Method Details

#attributes(options = {}) ⇒ Object

Have to implement Model#attributes to play nice with ActiveModel serializers



156
157
158
159
160
161
162
163
164
165
166
167
168
# File 'lib/lazy_record.rb', line 156

def attributes(options={})
  opts = {:include_pk => true}.merge options
  if opts[:include_pk]
    attrs = self.class.all_attributes
  else
    attrs = self.class.attributes
  end
  {}.tap do |h|
    attrs.each do |a_name|
      h[a_name] = instance_variable_get "@#{a_name}"
    end
  end
end

#build_associated(tbl) ⇒ Object

This method uses the model instance’s class::has_many() method to determine what the join table is called. The default join table name that this method uses if no options were given to Model::has_many() (see Model::has_many() for the passable options) is the following:

the tbl argument (for example, :tags), concatenated with ‘self`’s class’s table name (for example, ‘articles’) to make ‘tags_articles’

The default foreign key uses a similar heuristic. For the example above, it would be ‘tag_id’, because the given table name is ‘tags’, and the singular is ‘tag’. This is then concatenated with ‘_id’

To override the defaults, provide options to Model::has_many()



247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
# File 'lib/lazy_record.rb', line 247

def build_associated tbl
  self_tbl = self.class.table_name
  through = if _through = self.class.
           instance_variable_get("@join_tables")[tbl][:through]
    _through
  else
    "#{tbl}_#{self_tbl}"
  end
  fk = if _fk = self.class.
         instance_variable_get("@join_tables")[tbl][:fk]
    _fk
  else
    "#{tbl.to_s.singularize}_id"
  end

  tbl_model_name = tbl.to_s.singularize.camelize
  begin
    tbl_model = Object.const_get tbl_model_name
  rescue NameError
    retry if require "app/models/#{tbl_model_name.downcase}"
  end
  pk = self.class.primary_key
  id = __send__ pk
  sql = "SELECT * FROM #{tbl} INNER JOIN #{through} ON #{tbl}.#{tbl_model.primary_key} = " \
    "#{through}.#{fk} WHERE #{through}.#{self_tbl.singularize + '_id'} = ?"
  puts sql
  res = nil
  self.class.db_try do
    res = Db.conn.execute sql, id
  end
  objs = tbl_model.build_from res
  p objs
  objs = Array.wrap(objs) unless Array === objs
  __send__("#{tbl}=", __send__(tbl) + objs) unless objs.blank?
end

#build_from_params!(params) ⇒ Object

meant for internal use



148
149
150
151
152
# File 'lib/lazy_record.rb', line 148

def build_from_params!(params)
  params.each do |k, v|
    self.__send__("#{k}=".intern, v)
  end
end

#destroy(options = {}) ⇒ Object

delete the current model instance from the database



194
195
196
197
198
199
200
201
202
203
204
205
206
# File 'lib/lazy_record.rb', line 194

def destroy(options={})
  if options[:where]
  else
    sql = "DELETE FROM #{self.class.table_name} WHERE " \
          "#{self.primary_key} = ?"
    result = nil
    self.class.db_try do
      result = Db.conn.execute sql,
        instance_variable_get("@#{self.primary_key}")
    end
    result
  end
end

#saveObject

save current model instance into database



171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
# File 'lib/lazy_record.rb', line 171

def save
  return unless valid?
  sql = "INSERT INTO #{self.class.table_name} ("
  fields = self.class.attributes
  sql += fields.join(', ') + ') VALUES ('
  fields.each {|f| sql += '?, '}
  sql = sql[0...-2] + ')'
  values = fields.map do |f|
    ivar = instance_variable_get "@#{f}"
    if ivar.nil?
      "NULL"
    else
      ivar
    end
  end
  result = nil
  self.class.db_try do
    result = Db.conn.execute sql, *values
  end
  result ? true : false
end

#update_attributes(params, extra_where = {}) ⇒ Object

update the current model instance in the database



209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
# File 'lib/lazy_record.rb', line 209

def update_attributes(params, extra_where={})
  values = []
  key = self.primary_key
  id = params.delete key
  if extra_where.blank?
    sql = "UPDATE #{self.class.table_name} SET "
    params.each do |k,v|
      sql += "#{k} = ?, "
      values << v
    end
    sql = sql[0...-2]
    sql += " WHERE #{key} = ?"
    values << id
  else
  end
  res = nil
  self.class.db_try do
    res = Db.conn.execute sql, *values
  end
  res
end