Module: Sequel::Model::ClassMethods

Defined in:
lib/sequel/model/base.rb,
lib/sequel/model/plugins.rb,
lib/sequel/model/deprecated.rb

Instance Attribute Summary collapse

Instance Method Summary collapse

Instance Attribute Details

#allowed_columnsObject (readonly)

Which columns should be the only columns allowed in a call to set (default: all columns).



11
12
13
# File 'lib/sequel/model/base.rb', line 11

def allowed_columns
  @allowed_columns
end

#dataset_method_modulesObject (readonly)

Array of modules that extend this model’s dataset.



14
15
16
# File 'lib/sequel/model/base.rb', line 14

def dataset_method_modules
  @dataset_method_modules
end

#dataset_methodsObject (readonly)

Hash of dataset methods to add to this class and subclasses when set_dataset is called.



18
19
20
# File 'lib/sequel/model/base.rb', line 18

def dataset_methods
  @dataset_methods
end

#primary_keyObject (readonly)

The default primary key for classes (default: :id)



21
22
23
# File 'lib/sequel/model/base.rb', line 21

def primary_key
  @primary_key
end

#raise_on_save_failureObject

Whether to raise an error instead of returning nil on a failure to save/create/save_changes/etc.



25
26
27
# File 'lib/sequel/model/base.rb', line 25

def raise_on_save_failure
  @raise_on_save_failure
end

#raise_on_typecast_failureObject

Whether to raise an error when unable to typecast data for a column (default: true)



29
30
31
# File 'lib/sequel/model/base.rb', line 29

def raise_on_typecast_failure
  @raise_on_typecast_failure
end

#restricted_columnsObject (readonly)

Which columns should not be update in a call to set (default: no columns).



33
34
35
# File 'lib/sequel/model/base.rb', line 33

def restricted_columns
  @restricted_columns
end

#simple_pkObject (readonly)

Should be the literal primary key column name if this Model’s table has a simple primary key, or nil if the model has a compound primary key or no primary key.



37
38
39
# File 'lib/sequel/model/base.rb', line 37

def simple_pk
  @simple_pk
end

#simple_tableObject (readonly)

Should be the literal table name if this Model’s dataset is a simple table (no select, order, join, etc.), or nil otherwise.



41
42
43
# File 'lib/sequel/model/base.rb', line 41

def simple_table
  @simple_table
end

#strict_param_settingObject

Whether new/set/update and their variants should raise an error if an invalid key is used (either that doesn’t exist or that access is restricted to it).



46
47
48
# File 'lib/sequel/model/base.rb', line 46

def strict_param_setting
  @strict_param_setting
end

#typecast_empty_string_to_nilObject

Whether to typecast the empty string (”) to nil for columns that are not string or blob.



50
51
52
# File 'lib/sequel/model/base.rb', line 50

def typecast_empty_string_to_nil
  @typecast_empty_string_to_nil
end

#typecast_on_assignmentObject

Whether to typecast attribute values on assignment (default: true)



53
54
55
# File 'lib/sequel/model/base.rb', line 53

def typecast_on_assignment
  @typecast_on_assignment
end

#use_transactionsObject

Whether to use a transaction by default when saving/deleting records



56
57
58
# File 'lib/sequel/model/base.rb', line 56

def use_transactions
  @use_transactions
end

Instance Method Details

#[](*args) ⇒ Object

Returns the first record from the database matching the conditions. If a hash is given, it is used as the conditions. If another object is given, it finds the first record whose primary key(s) match the given argument(s).



62
63
64
65
66
67
68
69
70
# File 'lib/sequel/model/base.rb', line 62

def [](*args)
  args = args.first if (args.size == 1)
  return dataset[args] if args.is_a?(Hash)
  if t = simple_table and p = simple_pk
    with_sql("SELECT * FROM #{t} WHERE #{p} = #{dataset.literal(args)} LIMIT 1").first
  else
    dataset[primary_key_hash(args)]
  end
end

#columnsObject

Returns the columns in the result set in their original order. Generally, this will used the columns determined via the database schema, but in certain cases (e.g. models that are based on a joined dataset) it will use Dataset#columns to find the columns, which may be empty if the Dataset has no records.



77
78
79
# File 'lib/sequel/model/base.rb', line 77

def columns
  @columns || set_columns(dataset.naked.columns)
end

#create(values = {}, &block) ⇒ Object

Creates new instance with values set to passed-in Hash, saves it (running any callbacks), and returns the instance if the object was saved correctly. If there was an error saving the object, returns false.



85
86
87
88
89
# File 'lib/sequel/model/base.rb', line 85

def create(values = {}, &block)
  obj = new(values, &block)
  return unless obj.save
  obj
end

#create_tableObject

Creates table, using the column information from set_schema.



64
65
66
67
68
69
# File 'lib/sequel/model/deprecated.rb', line 64

def create_table
  Deprecation.deprecate('Sequel::Model.create_table', 'Use Model.plugin(:schema) first')
  db.create_table(table_name, :generator=>@schema)
  @db_schema = get_db_schema(true)
  columns
end

#create_table!Object

Drops the table if it exists and then runs create_table. Should probably not be used except in testing.



73
74
75
76
77
# File 'lib/sequel/model/deprecated.rb', line 73

def create_table!
  Deprecation.deprecate('Sequel::Model.create_table!', 'Use Model.plugin(:schema) first')
  drop_table rescue nil 
  create_table
end

#datasetObject

Returns the dataset associated with the Model class.



92
93
94
# File 'lib/sequel/model/base.rb', line 92

def dataset
  @dataset || raise(Error, "No dataset associated with #{self}")
end

#dbObject

Returns the database associated with the Model class.

Raises:



97
98
99
100
101
102
# File 'lib/sequel/model/base.rb', line 97

def db
  return @db if @db
  @db = self == Model ? DATABASES.first : superclass.db
  raise(Error, "No database associated with #{self}") unless @db
  @db
end

#db=(db) ⇒ Object

Sets the database associated with the Model class.



105
106
107
108
# File 'lib/sequel/model/base.rb', line 105

def db=(db)
  @db = db
  set_dataset(db.dataset(@dataset.opts)) if @dataset
end

#db_schemaObject

Returns the cached schema information if available or gets it from the database.



112
113
114
# File 'lib/sequel/model/base.rb', line 112

def db_schema
  @db_schema ||= get_db_schema
end

#def_dataset_method(*args, &block) ⇒ Object

If a block is given, define a method on the dataset with the given argument name using the given block as well as a method on the model that calls the dataset method.

If a block is not given, define a method on the model for each argument that calls the dataset method of the same argument name.

Raises:



122
123
124
125
126
127
128
129
130
131
# File 'lib/sequel/model/base.rb', line 122

def def_dataset_method(*args, &block)
  raise(Error, "No arguments given") if args.empty?
  if block_given?
    raise(Error, "Defining a dataset method using a block requires only one argument") if args.length > 1
    meth = args.first
    @dataset_methods[meth] = block
    dataset.meta_def(meth, &block)
  end
  args.each{|arg| instance_eval("def #{arg}(*args, &block); dataset.#{arg}(*args, &block) end", __FILE__, __LINE__) unless method_defined?(arg)}
end

#delete_allObject



23
24
25
26
# File 'lib/sequel/model/deprecated.rb', line 23

def delete_all
  Deprecation.deprecate('Sequel::Model.delete_all', 'Use Sequel::Model.delete')
  dataset.delete
end

#destroy_allObject



28
29
30
31
# File 'lib/sequel/model/deprecated.rb', line 28

def destroy_all
  Deprecation.deprecate('Sequel::Model.destroy_all', 'Use Sequel::Model.destroy')
  dataset.destroy
end

#drop_tableObject

Drops table.



80
81
82
83
# File 'lib/sequel/model/deprecated.rb', line 80

def drop_table
  Deprecation.deprecate('Sequel::Model.drop_table', 'Use Model.plugin(:schema) first')
  db.drop_table(table_name)
end

#find(*args, &block) ⇒ Object

Finds a single record according to the supplied filter, e.g.:

Ticket.find :author => 'Sharon' # => record


136
137
138
# File 'lib/sequel/model/base.rb', line 136

def find(*args, &block)
  filter(*args, &block).first
end

#find_or_create(cond) ⇒ Object

Like find but invokes create with given conditions when record does not exists.



142
143
144
# File 'lib/sequel/model/base.rb', line 142

def find_or_create(cond)
  find(cond) || create(cond)
end

#implicit_table_nameObject

Returns the implicit table name for the model class.



173
174
175
# File 'lib/sequel/model/base.rb', line 173

def implicit_table_name
  pluralize(underscore(demodulize(name))).to_sym
end

#inherited(subclass) ⇒ Object

If possible, set the dataset for the model subclass as soon as it is created. Also, inherit the INHERITED_INSTANCE_VARIABLES from the parent class.



149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
# File 'lib/sequel/model/base.rb', line 149

def inherited(subclass)
  ivs = subclass.instance_variables.collect{|x| x.to_s}
  EMPTY_INSTANCE_VARIABLES.each{|iv| subclass.instance_variable_set(iv, nil) unless ivs.include?(iv.to_s)}
  INHERITED_INSTANCE_VARIABLES.each do |iv, dup|
    next if ivs.include?(iv.to_s)
    sup_class_value = instance_variable_get(iv)
    sup_class_value = sup_class_value.dup if dup == :dup && sup_class_value
    subclass.instance_variable_set(iv, sup_class_value)
  end
  unless ivs.include?("@dataset")
    db
    begin
      if self == Model
        subclass.set_dataset(subclass.implicit_table_name) unless subclass.name.empty?
      elsif ds = instance_variable_get(:@dataset)
        subclass.set_dataset(ds.clone, :inherited=>true)
      end
    rescue
      nil
    end
  end
end

#is(*args, &block) ⇒ Object



13
14
15
16
# File 'lib/sequel/model/deprecated.rb', line 13

def is(*args, &block)
  Deprecation.deprecate('Sequel::Model.is', 'Use Sequel::Model.plugin')
  plugin(*args, &block)
end

#is_a(*args, &block) ⇒ Object



18
19
20
21
# File 'lib/sequel/model/deprecated.rb', line 18

def is_a(*args, &block)
  Deprecation.deprecate('Sequel::Model.is_a', 'Use Sequel::Model.plugin')
  plugin(*args, &block)
end

#load(values) ⇒ Object

Initializes a model instance as an existing record. This constructor is used by Sequel to initialize model instances when fetching records. #load requires that values be a hash where all keys are symbols. It probably should not be used by external code.



181
182
183
# File 'lib/sequel/model/base.rb', line 181

def load(values)
  new(values, true)
end

#no_primary_keyObject

Mark the model as not having a primary key. Not having a primary key can cause issues, among which is that you won’t be able to update records.



187
188
189
# File 'lib/sequel/model/base.rb', line 187

def no_primary_key
  @simple_pk = @primary_key = nil
end

#primary_key_hash(value) ⇒ Object

Returns primary key attribute hash. If using a composite primary key value such be an array with values for each primary key in the correct order. For a standard primary key, value should be an object with a compatible type for the key. If the model does not have a primary key, raises an Error.

Raises:



196
197
198
199
200
201
202
203
204
205
206
# File 'lib/sequel/model/base.rb', line 196

def primary_key_hash(value)
  raise(Error, "#{self} does not have a primary key") unless key = @primary_key
  case key
  when Array
    hash = {}
    key.each_with_index{|k,i| hash[k] = value[i]}
    hash
  else
    {key => value}
  end
end

#restrict_primary_keyObject

Restrict the setting of the primary key(s) inside new/set/update. Because this is the default, this only make sense to use in a subclass where the parent class has used unrestrict_primary_key.



211
212
213
# File 'lib/sequel/model/base.rb', line 211

def restrict_primary_key
  @restrict_primary_key = true
end

#restrict_primary_key?Boolean

Whether or not setting the primary key inside new/set/update is restricted, true by default.

Returns:

  • (Boolean)


217
218
219
# File 'lib/sequel/model/base.rb', line 217

def restrict_primary_key?
  @restrict_primary_key
end

#schemaObject

Returns table schema created with set_schema for direct descendant of Model. Does not retreive schema information from the database, see db_schema if you want that.



88
89
90
91
# File 'lib/sequel/model/deprecated.rb', line 88

def schema
  Deprecation.deprecate('Sequel::Model.schema', 'Use Model.plugin(:schema) first')
  @schema || (superclass.schema unless superclass == Model)
end

#serialize(*columns) ⇒ Object

Serializes column with YAML or through marshalling. Arguments should be column symbols, with an optional trailing hash with a :format key set to :yaml or :marshal (:yaml is the default). Setting this adds a transform to the model and dataset so that columns values will be serialized when saved and deserialized when returned from the database.



226
227
228
229
230
231
232
233
# File 'lib/sequel/model/base.rb', line 226

def serialize(*columns)
  format = extract_options!(columns)[:format] || :yaml
  @transform = columns.inject({}) do |m, c|
    m[c] = format
    m
  end
  @dataset.transform(@transform) if @dataset
end

#serialized?(column) ⇒ Boolean

Whether or not the given column is serialized for this model.

Returns:

  • (Boolean)


236
237
238
# File 'lib/sequel/model/base.rb', line 236

def serialized?(column)
  @transform ? @transform.include?(column) : false
end

#set_allowed_columns(*cols) ⇒ Object

Set the columns to allow in new/set/update. Using this means that any columns not listed here will not be modified. If you have any virtual setter methods (methods that end in =) that you want to be used in new/set/update, they need to be listed here as well (without the =).

It may be better to use (set|update)_only instead of this in places where only certain columns may be allowed.



247
248
249
# File 'lib/sequel/model/base.rb', line 247

def set_allowed_columns(*cols)
  @allowed_columns = cols
end

#set_cache(store, opts = {}) ⇒ Object



58
59
60
61
# File 'lib/sequel/model/deprecated.rb', line 58

def set_cache(store, opts = {})
  Deprecation.deprecate('Sequel::Model.set_cache', 'Use Model.plugin(:caching, store, opts)')
  plugin :caching, store, opts
end

#set_cache_ttl(ttl) ⇒ Object



53
54
55
56
# File 'lib/sequel/model/deprecated.rb', line 53

def set_cache_ttl(ttl)
  Deprecation.deprecate('Sequel::Model.set_cache_ttl', 'Use Model.plugin(:caching, store, opts) first')
  @cache_ttl = ttl
end

#set_dataset(ds, opts = {}) ⇒ Object Also known as: dataset=

Sets the dataset associated with the Model class. ds can be a Symbol (specifying a table name in the current database), or a Dataset. If a dataset is used, the model’s database is changed to the given dataset. If a symbol is used, a dataset is created from the current database with the table name given. Other arguments raise an Error.

This sets the model of the the given/created dataset to the current model and adds a destroy method to it. It also extends the dataset with the Associations::EagerLoading methods, and assigns a transform to it if there is one associated with the model. Finally, it attempts to determine the database schema based on the given/created dataset.



262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
# File 'lib/sequel/model/base.rb', line 262

def set_dataset(ds, opts={})
  inherited = opts[:inherited]
  @dataset = case ds
  when Symbol
    @simple_table = db.literal(ds)
    db[ds]
  when Dataset
    @simple_table = nil
    @db = ds.db
    ds
  else
    raise(Error, "Model.set_dataset takes a Symbol or a Sequel::Dataset")
  end
  @dataset.row_proc = Proc.new{|r| load(r)}
  @dataset.transform(@transform) if @transform
  if inherited
    @simple_table = superclass.simple_table
    @columns = @dataset.columns rescue nil
  else
    @dataset_method_modules.each{|m| @dataset.extend(m)} if @dataset_method_modules
    @dataset_methods.each{|meth, block| @dataset.meta_def(meth, &block)} if @dataset_methods
  end
  @dataset.model = self if @dataset.respond_to?(:model=)
  @db_schema = (inherited ? superclass.db_schema : get_db_schema) rescue nil
  self
end

#set_primary_key(*key) ⇒ Object

Sets primary key, regular and composite are possible.

Example:

class Tagging < Sequel::Model
  # composite key
  set_primary_key :taggable_id, :tag_id
end

class Person < Sequel::Model
  # regular key
  set_primary_key :person_id
end

You can set it to nil to not have a primary key, but that cause certain things not to work, see #no_primary_key.



305
306
307
308
# File 'lib/sequel/model/base.rb', line 305

def set_primary_key(*key)
  @simple_pk = key.length == 1 ? db.literal(key.first) : nil 
  @primary_key = (key.length == 1) ? key[0] : key.flatten
end

#set_restricted_columns(*cols) ⇒ Object

Set the columns to restrict in new/set/update. Using this means that any columns listed here will not be modified. If you have any virtual setter methods (methods that end in =) that you want not to be used in new/set/update, they need to be listed here as well (without the =).

It may be better to use (set|update)_except instead of this in places where only certain columns may be allowed.



317
318
319
# File 'lib/sequel/model/base.rb', line 317

def set_restricted_columns(*cols)
  @restricted_columns = cols
end

#set_schema(name = nil, &block) ⇒ Object

Defines a table schema (see Schema::Generator for more information).

This is only needed if you want to use the create_table/create_table! methods. Will also set the dataset if you provide a name, as well as setting the primary key if you defined one in the passed block.

In general, it is a better idea to use migrations for production code, as migrations allow changes to existing schema. set_schema is mostly useful for test code or simple examples.



102
103
104
105
106
107
# File 'lib/sequel/model/deprecated.rb', line 102

def set_schema(name = nil, &block)
  Deprecation.deprecate('Sequel::Model.set_schema', 'Use Model.plugin(:schema) first')
  set_dataset(db[name]) if name
  @schema = Sequel::Schema::Generator.new(db, &block)
  set_primary_key(@schema.primary_key_name) if @schema.primary_key_name
end

#set_sti_key(key) ⇒ Object



38
39
40
41
# File 'lib/sequel/model/deprecated.rb', line 38

def set_sti_key(key)
  Deprecation.deprecate('Sequel::Model.set_sti_key', 'Use Model.plugin(:single_table_inheritance, key)')
  plugin :single_table_inheritance, key
end

#sti_datasetObject



48
49
50
51
# File 'lib/sequel/model/deprecated.rb', line 48

def sti_dataset
  Deprecation.deprecate('Sequel::Model.sti_dataset', 'Use Model.plugin(:single_table_inheritance, key) first')
  @sti_dataset
end

#sti_keyObject



43
44
45
46
# File 'lib/sequel/model/deprecated.rb', line 43

def sti_key
  Deprecation.deprecate('Sequel::Model.sti_key', 'Use Model.plugin(:single_table_inheritance, key) first')
  @sti_key
end

#str_columnsObject



33
34
35
36
# File 'lib/sequel/model/deprecated.rb', line 33

def str_columns
  Deprecation.deprecate('Sequel::Model.str_columns', 'Use model.columns.map{|x| x.to_s}')
  @str_columns ||= columns.map{|c| c.to_s.freeze}
end

#subset(name, *args, &block) ⇒ Object

Defines a method that returns a filtered dataset. Subsets create dataset methods, so they can be chained for scoping. For example:

Topic.subset(:popular){|o| o.num_posts > 100}
Topic.subset(:recent){|o| o.created_on > Date.today - 7}

Allows you to do:

Topic.filter(:username.like('%joe%')).popular.recent

to get topics with a username that includes joe that have more than 100 posts and were created less than 7 days ago.



335
336
337
# File 'lib/sequel/model/base.rb', line 335

def subset(name, *args, &block)
  def_dataset_method(name){filter(*args, &block)}
end

#table_exists?Boolean

Returns true if table exists, false otherwise.

Returns:

  • (Boolean)


110
111
112
113
# File 'lib/sequel/model/deprecated.rb', line 110

def table_exists?
  Deprecation.deprecate('Sequel::Model.table_exists?', 'Use Model.plugin(:schema) first')
  db.table_exists?(table_name)
end

#table_nameObject

Returns name of primary table for the dataset.



340
341
342
# File 'lib/sequel/model/base.rb', line 340

def table_name
  dataset.opts[:from].first
end

#unrestrict_primary_keyObject

Allow the setting of the primary key(s) inside new/set/update.



345
346
347
# File 'lib/sequel/model/base.rb', line 345

def unrestrict_primary_key
  @restrict_primary_key = false
end