Class: Sequel::Model
- Extended by:
- Enumerable, Associations
- Defined in:
- lib/sequel_model.rb,
lib/sequel_model/base.rb,
lib/sequel_model/hooks.rb,
lib/sequel_model/record.rb,
lib/sequel_model/schema.rb,
lib/sequel_model/caching.rb,
lib/sequel_model/plugins.rb,
lib/sequel_model/validations.rb
Overview
Model has some methods that are added via metaprogramming:
-
All of the methods in DATASET_METHODS have class methods created that call the Model’s dataset with the method of the same name with the given arguments.
-
All of the methods in HOOKS have class methods created that accept either a method name symbol or an optional tag and a block. These methods run the code as a callback at the specified time. For example:
Model.before_save :do_something Model.before_save(:do_something_else){ self.something_else = 42} object = Model.new object.save
Would run the object’s :do_something method following by the code block related to :do_something_else. Note that if you specify a block, a tag is optional. If the tag is not nil, it will overwrite a previous block with the same tag. This allows hooks to work with systems that reload code.
-
All of the methods in HOOKS also create instance methods, but you should not override these instance methods.
-
The following instance_methods all call the class method of the same name: columns, dataset, db, primary_key, str_columns.
-
The following class level attr_readers are created: allowed_columns, cache_store, cache_ttl, dataset_methods, primary_key, restricted_columns, sti_dataset, and sti_key. You should not usually need to access these directly.
-
The following class level attr_accessors are created: raise_on_typecast_failure, raise_on_save_failure, strict_param_setting, typecast_empty_string_to_nil, and typecast_on_assignment:
# Don't raise an error if a validation attempt fails in # save/create/save_changes/etc. Model.raise_on_save_failure = false Model.before_save{false} Model.new.save # => nil # Don't raise errors in new/set/update/etc. if an attempt to # access a missing/restricted method occurs (just silently # skip it) Model.strict_param_setting = false Model.new(:id=>1) # No Error # Don't typecast attribute values on assignment Model.typecast_on_assignment = false m = Model.new m.number = '10' m.number # => '10' instead of 10 # Don't typecast empty string to nil for non-string, non-blob columns. Model.typecast_empty_string_to_nil = false m.number = '' m.number # => '' instead of nil # Don't raise if unable to typecast data for a column Model.typecast_empty_string_to_nil = true Model.raise_on_typecast_failure = false m.not_null_column = '' # => nil m.number = 'A' # => 'A'
-
The following class level method aliases are defined:
-
Model.dataset= => set_dataset
-
Model.is_a => is
-
Defined Under Namespace
Modules: Associations, DatasetMethods, Validation
Constant Summary collapse
- DATASET_METHODS =
Dataset methods to proxy via metaprogramming
%w'<< all avg count delete distinct eager eager_graph each each_page empty? except exclude filter first from from_self full_outer_join get graph group group_and_count group_by having import inner_join insert insert_multiple intersect interval invert_order join join_table last left_outer_join limit map multi_insert naked order order_by order_more paginate print query range reverse_order right_outer_join select select_all select_more server set set_graph_aliases single_value size to_csv to_hash transform union uniq unfiltered unordered update where'.map{|x| x.to_sym}
- INHERITED_INSTANCE_VARIABLES =
Instance variables that are inherited in subclasses
{:@allowed_columns=>:dup, :@cache_store=>nil, :@cache_ttl=>nil, :@dataset_methods=>:dup, :@primary_key=>nil, :@raise_on_save_failure=>nil, :@restricted_columns=>:dup, :@restrict_primary_key=>nil, :@sti_dataset=>nil, :@sti_key=>nil, :@strict_param_setting=>nil, :@typecast_empty_string_to_nil=>nil, :@typecast_on_assignment=>nil, :@raise_on_typecast_failure=>nil, :@association_reflections=>:dup}
- HOOKS =
Hooks that are safe for public use
[:after_initialize, :before_create, :after_create, :before_update, :after_update, :before_save, :after_save, :before_destroy, :after_destroy, :before_validation, :after_validation]
- PRIVATE_HOOKS =
Hooks that are only for internal use
[:before_update_values, :before_delete]
- RESTRICTED_SETTER_METHODS =
The setter methods (methods ending with =) that are never allowed to be called automatically via set.
%w"== === []= taguri= typecast_empty_string_to_nil= typecast_on_assignment= strict_param_setting= raise_on_save_failure= raise_on_typecast_failure="
- DEFAULT_VALIDATION_IF_PROC =
Validations without an :if option are always run
proc{true}
Constants included from Associations
Associations::ASSOCIATION_TYPES
Instance Attribute Summary collapse
-
#values ⇒ Object
readonly
The hash of attribute values.
Class Method Summary collapse
-
.[](*args) ⇒ Object
Returns the first record from the database matching the conditions.
-
.columns ⇒ Object
Returns the columns in the result set in their original order.
-
.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.
-
.create_table ⇒ Object
Creates table, using the column information from set_schema.
-
.create_table! ⇒ Object
Drops the table if it exists and then runs create_table.
-
.dataset ⇒ Object
Returns the dataset associated with the Model class.
-
.db ⇒ Object
Returns the database associated with the Model class.
-
.db=(db) ⇒ Object
Sets the database associated with the Model class.
-
.db_schema ⇒ Object
Returns the cached schema information if available or gets it from the database.
-
.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.
-
.delete_all ⇒ Object
Deletes all records in the model’s table.
-
.destroy_all ⇒ Object
Like delete_all, but invokes before_destroy and after_destroy hooks if used.
-
.drop_table ⇒ Object
Drops table.
-
.eager_loading_dataset(opts, ds, select, associations) ⇒ Object
Modify and return eager loading dataset based on association options.
-
.fetch(*args) ⇒ Object
Returns a dataset with custom SQL that yields model objects.
-
.find(*args, &block) ⇒ Object
Finds a single record according to the supplied filter, e.g.:.
-
.find_or_create(cond) ⇒ Object
Like find but invokes create with given conditions when record does not exists.
-
.has_hooks?(hook) ⇒ Boolean
Returns true if there are any hook blocks for the given hook.
-
.has_validations? ⇒ Boolean
Returns true if validations are defined.
-
.hook_blocks(hook) ⇒ Object
Yield every block related to the given hook.
-
.implicit_table_name ⇒ Object
Returns the implicit table name for the model class.
-
.inherited(subclass) ⇒ Object
If possible, set the dataset for the model subclass as soon as it is created.
-
.is(plugin, *args) ⇒ Object
Loads a plugin for use with the model class, passing optional arguments to the plugin.
-
.load(values) ⇒ Object
Initializes a model instance as an existing record.
-
.no_primary_key ⇒ Object
Mark the model as not having a primary key.
-
.primary_key_hash(value) ⇒ Object
Returns primary key attribute hash.
-
.restrict_primary_key ⇒ Object
Restrict the setting of the primary key(s) inside new/set/update.
-
.restrict_primary_key? ⇒ Boolean
Whether or not setting the primary key inside new/set/update is restricted, true by default.
-
.schema ⇒ Object
Returns table schema created with set_schema for direct descendant of Model.
-
.serialize(*columns) ⇒ Object
Serializes column with YAML or through marshalling.
-
.serialized?(column) ⇒ Boolean
Whether or not the given column is serialized for this model.
-
.set_allowed_columns(*cols) ⇒ Object
Set the columns to allow in new/set/update.
-
.set_cache(store, opts = {}) ⇒ Object
Set the cache store for the model, as well as the caching before_* hooks.
-
.set_cache_ttl(ttl) ⇒ Object
Set the time to live for the cache store, in seconds (default is 3600, so 1 hour).
-
.set_dataset(ds, opts = {}) ⇒ Object
Sets the dataset associated with the Model class.
-
.set_primary_key(*key) ⇒ Object
Sets primary key, regular and composite are possible.
-
.set_restricted_columns(*cols) ⇒ Object
Set the columns to restrict in new/set/update.
-
.set_schema(name = nil, &block) ⇒ Object
Defines a table schema (see Schema::Generator for more information).
-
.set_sti_key(key) ⇒ Object
Makes this model a polymorphic model with the given key being a string field in the database holding the name of the class to use.
-
.skip_superclass_validations ⇒ Object
Instructs the model to skip validations defined in superclasses.
-
.str_columns ⇒ Object
Returns the columns as a list of frozen strings instead of a list of symbols.
-
.subset(name, *args, &block) ⇒ Object
Defines a method that returns a filtered dataset.
-
.table_exists? ⇒ Boolean
Returns true if table exists, false otherwise.
-
.table_name ⇒ Object
Returns name of primary table for the dataset.
-
.unrestrict_primary_key ⇒ Object
Allow the setting of the primary key(s) inside new/set/update.
-
.validate(o) ⇒ Object
Validates the given instance.
-
.validates(&block) ⇒ Object
Defines validations by converting a longhand block into a series of shorthand definitions.
-
.validates_acceptance_of(*atts) ⇒ Object
Validates acceptance of an attribute.
-
.validates_confirmation_of(*atts) ⇒ Object
Validates confirmation of an attribute.
-
.validates_each(*atts, &block) ⇒ Object
Adds a validation for each of the given attributes using the supplied block.
-
.validates_format_of(*atts) ⇒ Object
Validates the format of an attribute, checking the string representation of the value against the regular expression provided by the :with option.
-
.validates_length_of(*atts) ⇒ Object
Validates the length of an attribute.
-
.validates_numericality_of(*atts) ⇒ Object
Validates whether an attribute is a number.
-
.validates_presence_of(*atts) ⇒ Object
Validates the presence of an attribute.
-
.validates_uniqueness_of(*atts) ⇒ Object
Validates only if the fields in the model (specified by atts) are unique in the database.
-
.validations ⇒ Object
Returns the validations hash for the class.
Instance Method Summary collapse
-
#==(obj) ⇒ Object
(also: #eql?)
Compares model instances by values.
-
#===(obj) ⇒ Object
If pk is not nil, true only if the objects have the same class and pk.
-
#[](column) ⇒ Object
Returns value of the column’s attribute.
-
#[]=(column, value) ⇒ Object
Sets value of the column’s attribute and marks the column as changed.
-
#associations ⇒ Object
The current cached associations.
-
#cache_key ⇒ Object
Return a key unique to the underlying record for caching, based on the primary key value(s) for the object.
-
#changed_columns ⇒ Object
The columns that have been updated.
-
#delete ⇒ Object
Deletes and returns self.
-
#destroy ⇒ Object
Like delete but runs hooks before and after delete.
-
#each(&block) ⇒ Object
Enumerates through all attributes.
-
#errors ⇒ Object
Returns the validation errors associated with the object.
-
#exists? ⇒ Boolean
Returns true when current instance exists, false otherwise.
-
#hash ⇒ Object
Unique for objects with the same class and pk (if pk is not nil), or the same class and values (if pk is nil).
-
#id ⇒ Object
Returns value for the :id attribute, even if the primary key is not id.
-
#initialize(values = {}, from_db = false) ⇒ Model
constructor
Creates new instance with values set to passed-in Hash.
-
#inspect ⇒ Object
Returns a string representation of the model instance including the class name and values.
-
#keys ⇒ Object
Returns attribute names as an array of symbols.
-
#new? ⇒ Boolean
Returns true if the current instance represents a new record.
-
#pk ⇒ Object
Returns the primary key value identifying the model instance.
-
#pk_hash ⇒ Object
Returns a hash identifying the model instance.
-
#refresh ⇒ Object
(also: #reload)
Reloads attributes from database and returns self.
-
#save(*columns) ⇒ Object
Creates or updates the record, after making sure the record is valid.
-
#save!(*columns) ⇒ Object
Creates or updates the record, without attempting to validate it first.
-
#save_changes ⇒ Object
Saves only changed columns or does nothing if no columns are marked as chanaged.
-
#set(hash) ⇒ Object
(also: #set_with_params)
Updates the instance with the supplied values with support for virtual attributes, raising an exception if a value is used that doesn’t have a setter method (or ignoring it if strict_param_setting = false).
-
#set_all(hash) ⇒ Object
Set all values using the entries in the hash, ignoring any setting of allowed_columns or restricted columns in the model.
-
#set_except(hash, *except) ⇒ Object
Set all values using the entries in the hash, except for the keys given in except.
-
#set_only(hash, *only) ⇒ Object
Set the values using the entries in the hash, only if the key is included in only.
-
#set_values(values) ⇒ Object
Sets the value attributes without saving the record.
-
#this ⇒ Object
Returns (naked) dataset that should return only this instance.
-
#update(hash) ⇒ Object
(also: #update_with_params)
Runs set with the passed hash and runs save_changes (which runs any callback methods).
-
#update_all(hash) ⇒ Object
Update all values using the entries in the hash, ignoring any setting of allowed_columns or restricted columns in the model.
-
#update_except(hash, *except) ⇒ Object
Update all values using the entries in the hash, except for the keys given in except.
-
#update_only(hash, *only) ⇒ Object
Update the values using the entries in the hash, only if the key is included in only.
-
#update_values(values) ⇒ Object
Sets the values attributes with set_values and then updates the record in the database using those values.
-
#valid? ⇒ Boolean
Validates the object and returns true if no errors are reported.
-
#validate ⇒ Object
Validates the object.
Methods included from Enumerable
Methods included from Associations
all_association_reflections, associate, association_reflection, many_to_many, many_to_one, one_to_many
Constructor Details
#initialize(values = {}, from_db = false) ⇒ Model
Creates new instance with values set to passed-in Hash. If a block is given, yield the instance to the block unless from_db is true. This method runs the after_initialize hook after it has optionally yielded itself to the block.
Arguments:
-
values - should be a hash with symbol keys, though string keys will work if from_db is false.
-
from_db - should only be set by Model.load, forget it exists.
26 27 28 29 30 31 32 33 34 35 36 37 38 |
# File 'lib/sequel_model/record.rb', line 26 def initialize(values = {}, from_db = false) if from_db @new = false @values = values else @values = {} @new = true set(values) changed_columns.clear yield self if block_given? end after_initialize end |
Instance Attribute Details
#values ⇒ Object (readonly)
The hash of attribute values. Keys are symbols with the names of the underlying database columns.
9 10 11 |
# File 'lib/sequel_model/record.rb', line 9 def values @values end |
Class 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). If caching is used, the cache is checked first before a dataset lookup is attempted unless a hash is supplied.
86 87 88 89 90 91 92 93 94 |
# File 'lib/sequel_model/base.rb', line 86 def self.[](*args) args = args.first if (args.size == 1) if Hash === args dataset[args] else @cache_store ? cache_lookup(args) : dataset[primary_key_hash(args)] end end |
.columns ⇒ Object
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.
101 102 103 |
# File 'lib/sequel_model/base.rb', line 101 def self.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.
109 110 111 112 113 |
# File 'lib/sequel_model/base.rb', line 109 def self.create(values = {}, &block) obj = new(values, &block) return unless obj.save obj end |
.create_table ⇒ Object
Creates table, using the column information from set_schema.
4 5 6 7 8 |
# File 'lib/sequel_model/schema.rb', line 4 def self.create_table db.create_table(table_name, @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.
12 13 14 15 |
# File 'lib/sequel_model/schema.rb', line 12 def self.create_table! drop_table rescue nil create_table end |
.dataset ⇒ Object
Returns the dataset associated with the Model class.
116 117 118 |
# File 'lib/sequel_model/base.rb', line 116 def self.dataset @dataset || raise(Error, "No dataset associated with #{self}") end |
.db ⇒ Object
Returns the database associated with the Model class.
121 122 123 124 125 126 |
# File 'lib/sequel_model/base.rb', line 121 def self.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.
129 130 131 132 133 134 |
# File 'lib/sequel_model/base.rb', line 129 def self.db=(db) @db = db if @dataset set_dataset(db[table_name]) end end |
.db_schema ⇒ Object
Returns the cached schema information if available or gets it from the database.
138 139 140 |
# File 'lib/sequel_model/base.rb', line 138 def self.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.
148 149 150 151 152 153 154 155 156 157 |
# File 'lib/sequel_model/base.rb', line 148 def self.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.(meth, &block) end args.each{|arg| instance_eval("def #{arg}(*args, &block); dataset.#{arg}(*args, &block) end", __FILE__, __LINE__)} end |
.delete_all ⇒ Object
Deletes all records in the model’s table.
160 161 162 |
# File 'lib/sequel_model/base.rb', line 160 def self.delete_all dataset.delete end |
.destroy_all ⇒ Object
Like delete_all, but invokes before_destroy and after_destroy hooks if used.
165 166 167 |
# File 'lib/sequel_model/base.rb', line 165 def self.destroy_all dataset.destroy end |
.drop_table ⇒ Object
Drops table.
18 19 20 |
# File 'lib/sequel_model/schema.rb', line 18 def self.drop_table db.drop_table(table_name) end |
.eager_loading_dataset(opts, ds, select, associations) ⇒ Object
Modify and return eager loading dataset based on association options
175 176 177 178 179 180 181 182 183 |
# File 'lib/sequel_model/base.rb', line 175 def self.eager_loading_dataset(opts, ds, select, associations) ds = ds.select(*select) if select ds = ds.order(*opts[:order]) if opts[:order] ds = ds.eager(opts[:eager]) if opts[:eager] ds = ds.eager_graph(opts[:eager_graph]) if opts[:eager_graph] ds = ds.eager(associations) unless associations.blank? ds = opts[:eager_block].call(ds) if opts[:eager_block] ds end |
.fetch(*args) ⇒ Object
Returns a dataset with custom SQL that yields model objects.
170 171 172 |
# File 'lib/sequel_model/base.rb', line 170 def self.fetch(*args) db.fetch(*args).set_model(self) end |
.find(*args, &block) ⇒ Object
Finds a single record according to the supplied filter, e.g.:
Ticket.find :author => 'Sharon' # => record
188 189 190 |
# File 'lib/sequel_model/base.rb', line 188 def self.find(*args, &block) dataset.filter(*args, &block).first end |
.find_or_create(cond) ⇒ Object
Like find but invokes create with given conditions when record does not exists.
194 195 196 |
# File 'lib/sequel_model/base.rb', line 194 def self.find_or_create(cond) find(cond) || create(cond) end |
.has_hooks?(hook) ⇒ Boolean
Returns true if there are any hook blocks for the given hook.
12 13 14 |
# File 'lib/sequel_model/hooks.rb', line 12 def self.has_hooks?(hook) !@hooks[hook].empty? end |
.has_validations? ⇒ Boolean
Returns true if validations are defined.
60 61 62 |
# File 'lib/sequel_model/validations.rb', line 60 def self.has_validations? !validations.empty? end |
.hook_blocks(hook) ⇒ Object
Yield every block related to the given hook.
17 18 19 |
# File 'lib/sequel_model/hooks.rb', line 17 def self.hook_blocks(hook) @hooks[hook].each{|k,v| yield v} end |
.implicit_table_name ⇒ Object
Returns the implicit table name for the model class.
226 227 228 |
# File 'lib/sequel_model/base.rb', line 226 def self.implicit_table_name name.demodulize.underscore.pluralize.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.
201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 |
# File 'lib/sequel_model/base.rb', line 201 def self.inherited(subclass) sup_class = subclass.superclass ivs = subclass.instance_variables.collect{|x| x.to_s} INHERITED_INSTANCE_VARIABLES.each do |iv, dup| next if ivs.include?(iv.to_s) sup_class_value = sup_class.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") begin if sup_class == Model subclass.set_dataset(Model.db[subclass.implicit_table_name]) unless subclass.name.blank? elsif ds = sup_class.instance_variable_get(:@dataset) subclass.set_dataset(sup_class.sti_key ? sup_class.sti_dataset.filter(sup_class.sti_key=>subclass.name.to_s) : ds.clone, :inherited=>true) end rescue nil end end hooks = subclass.instance_variable_set(:@hooks, {}) sup_class.instance_variable_get(:@hooks).each{|k,v| hooks[k] = v.dup} end |
.is(plugin, *args) ⇒ Object
Loads a plugin for use with the model class, passing optional arguments to the plugin. If the plugin has a DatasetMethods module and the model doesn’t have a dataset, raise an Error.
21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 |
# File 'lib/sequel_model/plugins.rb', line 21 def self.is(plugin, *args) m = plugin_module(plugin) raise(Error, "Plugin cannot be applied because the model class has no dataset") if m.const_defined?("DatasetMethods") && !@dataset if m.respond_to?(:apply) m.apply(self, *args) end if m.const_defined?("InstanceMethods") class_def(:"#{plugin}_opts") {args.first} include(m::InstanceMethods) end if m.const_defined?("ClassMethods") (:"#{plugin}_opts") {args.first} extend(m::ClassMethods) end if m.const_defined?("DatasetMethods") dataset.(:"#{plugin}_opts") {args.first} dataset.extend(m::DatasetMethods) def_dataset_method(*m::DatasetMethods.public_instance_methods) end 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.
234 235 236 |
# File 'lib/sequel_model/base.rb', line 234 def self.load(values) new(values, true) end |
.no_primary_key ⇒ Object
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.
240 241 242 |
# File 'lib/sequel_model/base.rb', line 240 def self.no_primary_key @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.
249 250 251 252 253 254 255 256 257 258 259 |
# File 'lib/sequel_model/base.rb', line 249 def self.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_key ⇒ Object
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.
264 265 266 |
# File 'lib/sequel_model/base.rb', line 264 def self.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.
270 271 272 |
# File 'lib/sequel_model/base.rb', line 270 def self.restrict_primary_key? @restrict_primary_key end |
.schema ⇒ Object
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.
25 26 27 |
# File 'lib/sequel_model/schema.rb', line 25 def self.schema @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.
279 280 281 282 283 284 285 286 |
# File 'lib/sequel_model/base.rb', line 279 def self.serialize(*columns) format = 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.
289 290 291 |
# File 'lib/sequel_model/base.rb', line 289 def self.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.
300 301 302 |
# File 'lib/sequel_model/base.rb', line 300 def self.set_allowed_columns(*cols) @allowed_columns = cols end |
.set_cache(store, opts = {}) ⇒ Object
Set the cache store for the model, as well as the caching before_* hooks.
The cache store should implement the following API:
cache_store.set(key, obj, time) # Associate the obj with the given key
# in the cache for the time (specified
# in seconds)
cache_store.get(key) => obj # Returns object set with same key
cache_store.get(key2) => nil # nil returned if there isn't an object
# currently in the cache with that key
17 18 19 20 21 22 23 |
# File 'lib/sequel_model/caching.rb', line 17 def self.set_cache(store, opts = {}) @cache_store = store @cache_ttl = opts[:ttl] || 3600 before_save :cache_delete_unless_new before_update_values :cache_delete before_delete :cache_delete end |
.set_cache_ttl(ttl) ⇒ Object
Set the time to live for the cache store, in seconds (default is 3600, so 1 hour).
27 28 29 |
# File 'lib/sequel_model/caching.rb', line 27 def self.set_cache_ttl(ttl) @cache_ttl = ttl end |
.set_dataset(ds, opts = {}) ⇒ Object
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.
315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 |
# File 'lib/sequel_model/base.rb', line 315 def self.set_dataset(ds, opts={}) inherited = opts[:inherited] @dataset = case ds when Symbol db[ds] when Dataset @db = ds.db ds else raise(Error, "Model.set_dataset takes a Symbol or a Sequel::Dataset") end @dataset.set_model(self) @dataset.transform(@transform) if @transform if inherited @columns = @dataset.columns rescue nil else @dataset.extend(DatasetMethods) @dataset.extend(Associations::EagerLoading) @dataset_methods.each{|meth, block| @dataset.(meth, &block)} if @dataset_methods end @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.
355 356 357 |
# File 'lib/sequel_model/base.rb', line 355 def self.set_primary_key(*key) @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.
366 367 368 |
# File 'lib/sequel_model/base.rb', line 366 def self.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.
38 39 40 41 42 |
# File 'lib/sequel_model/schema.rb', line 38 def self.set_schema(name = nil, &block) set_dataset(db[name]) if name @schema = Schema::Generator.new(db, &block) set_primary_key(@schema.primary_key_name) if @schema.primary_key_name end |
.set_sti_key(key) ⇒ Object
Makes this model a polymorphic model with the given key being a string field in the database holding the name of the class to use. If the key given has a NULL value or there are any problems looking up the class, uses the current class.
This should be used to set up single table inheritance for the model, and it only makes sense to use this in the parent class.
You should call sti_key after any calls to set_dataset in the model, otherwise subclasses might not have the filters set up correctly.
The filters that sti_key sets up in subclasses will not work if those subclasses have further subclasses. For those middle subclasses, you will need to call set_dataset manually with the correct filter set.
384 385 386 387 388 389 390 |
# File 'lib/sequel_model/base.rb', line 384 def self.set_sti_key(key) m = self @sti_key = key @sti_dataset = dataset dataset.set_model(key, Hash.new{|h,k| h[k] = (k.constantize rescue m)}) before_create(:set_sti_key){send("#{key}=", model.name.to_s)} end |
.skip_superclass_validations ⇒ Object
Instructs the model to skip validations defined in superclasses
65 66 67 |
# File 'lib/sequel_model/validations.rb', line 65 def self.skip_superclass_validations @skip_superclass_validations = true end |
.str_columns ⇒ Object
Returns the columns as a list of frozen strings instead of a list of symbols. This makes it possible to check whether a column exists without creating a symbol, which would be a memory leak if called with user input.
396 397 398 |
# File 'lib/sequel_model/base.rb', line 396 def self.str_columns @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, :num_posts > 100)
Topic.subset(:recent, :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.
414 415 416 |
# File 'lib/sequel_model/base.rb', line 414 def self.subset(name, *args, &block) def_dataset_method(name){filter(*args, &block)} end |
.table_exists? ⇒ Boolean
Returns true if table exists, false otherwise.
45 46 47 |
# File 'lib/sequel_model/schema.rb', line 45 def self.table_exists? db.table_exists?(table_name) end |
.table_name ⇒ Object
Returns name of primary table for the dataset.
419 420 421 |
# File 'lib/sequel_model/base.rb', line 419 def self.table_name dataset.opts[:from].first end |
.unrestrict_primary_key ⇒ Object
Allow the setting of the primary key(s) inside new/set/update.
424 425 426 |
# File 'lib/sequel_model/base.rb', line 424 def self.unrestrict_primary_key @restrict_primary_key = false end |
.validate(o) ⇒ Object
Validates the given instance.
91 92 93 94 95 96 97 98 99 100 101 102 103 104 |
# File 'lib/sequel_model/validations.rb', line 91 def self.validate(o) if superclass.respond_to?(:validate) && !@skip_superclass_validations superclass.validate(o) end validations.each do |att, procs| v = case att when Array att.collect{|a| o.send(a)} else o.send(att) end procs.each {|tag, p| p.call(o, att, v)} end end |
.validates(&block) ⇒ Object
Defines validations by converting a longhand block into a series of shorthand definitions. For example:
class MyClass
include Validation
validates do
length_of :name, :minimum => 6
length_of :password, :minimum => 8
end
end
is equivalent to:
class MyClass
include Validation
validates_length_of :name, :minimum => 6
validates_length_of :password, :minimum => 8
end
86 87 88 |
# File 'lib/sequel_model/validations.rb', line 86 def self.validates(&block) Validation::Generator.new(self, &block) end |
.validates_acceptance_of(*atts) ⇒ Object
Validates acceptance of an attribute. Just checks that the value is equal to the :accept option.
Possible Options:
-
:accept - The value required for the object to be valid (default: ‘1’)
-
:allow_blank - Whether to skip the validation if the value is blank (default: false)
-
:allow_nil - Whether to skip the validation if the value is nil (default: true)
-
:if - A symbol (indicating an instance_method) or proc (which is instance_evaled) skipping this validation if it returns nil or false.
-
:message - The message to use (default: ‘is not accepted’)
-
:tag - The tag to use for this validation (default: :acceptance)
117 118 119 120 121 122 123 124 125 126 127 128 129 |
# File 'lib/sequel_model/validations.rb', line 117 def self.validates_acceptance_of(*atts) opts = { :message => 'is not accepted', :allow_nil => true, :accept => '1' }.merge!(atts.) atts << {:if=>opts[:if], :tag=>opts[:tag]||:acceptance} validates_each(*atts) do |o, a, v| next if (v.nil? && opts[:allow_nil]) || (v.blank? && opts[:allow_blank]) o.errors[a] << opts[:message] unless v == opts[:accept] end end |
.validates_confirmation_of(*atts) ⇒ Object
Validates confirmation of an attribute. Checks that the object has a _confirmation value matching the current value. For example:
validates_confirmation_of :blah
Just makes sure that object.blah = object.blah_confirmation. Often used for passwords or email addresses on web forms.
Possible Options:
-
:allow_false - Whether to skip the validation if the value is blank (default: false)
-
:allow_nil - Whether to skip the validation if the value is nil (default: false)
-
:if - A symbol (indicating an instance_method) or proc (which is instance_evaled) skipping this validation if it returns nil or false.
-
:message - The message to use (default: ‘is not confirmed’)
-
:tag - The tag to use for this validation (default: :confirmation)
146 147 148 149 150 151 152 153 154 155 156 157 |
# File 'lib/sequel_model/validations.rb', line 146 def self.validates_confirmation_of(*atts) opts = { :message => 'is not confirmed', }.merge!(atts.) atts << {:if=>opts[:if], :tag=>opts[:tag]||:confirmation} validates_each(*atts) do |o, a, v| next if (v.nil? && opts[:allow_nil]) || (v.blank? && opts[:allow_blank]) c = o.send(:"#{a}_confirmation") o.errors[a] << opts[:message] unless v == c end end |
.validates_each(*atts, &block) ⇒ Object
Adds a validation for each of the given attributes using the supplied block. The block must accept three arguments: instance, attribute and value, e.g.:
validates_each :name, :password do |object, attribute, value|
object.errors[attribute] << 'is not nice' unless value.nice?
end
Possible Options:
-
:if - A symbol (indicating an instance_method) or proc (which is instance_evaled) skipping this validation if it returns nil or false.
-
:tag - The tag to use for this validation (default: nil)
171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 |
# File 'lib/sequel_model/validations.rb', line 171 def self.validates_each(*atts, &block) opts = atts. blk = if opts[:if] proc{|o,a,v| block.call(o,a,v) if o.instance_eval(&if_proc(opts))} else block end tag = opts[:tag] atts.each do |a| a_vals = validations[a] if tag && (old = a_vals.find{|x| x[0] == tag}) old[1] = blk else a_vals << [tag, blk] end end end |
.validates_format_of(*atts) ⇒ Object
Validates the format of an attribute, checking the string representation of the value against the regular expression provided by the :with option.
Possible Options:
-
:allow_blank - Whether to skip the validation if the value is blank (default: false)
-
:allow_nil - Whether to skip the validation if the value is nil (default: false)
-
:if - A symbol (indicating an instance_method) or proc (which is instance_evaled) skipping this validation if it returns nil or false.
-
:message - The message to use (default: ‘is invalid’)
-
:tag - The tag to use for this validation (default: :format)
-
:with - The regular expression to validate the value with (required).
200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 |
# File 'lib/sequel_model/validations.rb', line 200 def self.validates_format_of(*atts) opts = { :message => 'is invalid', }.merge!(atts.) unless opts[:with].is_a?(Regexp) raise ArgumentError, "A regular expression must be supplied as the :with option of the options hash" end atts << {:if=>opts[:if], :tag=>opts[:tag]||:format} validates_each(*atts) do |o, a, v| next if (v.nil? && opts[:allow_nil]) || (v.blank? && opts[:allow_blank]) o.errors[a] << opts[:message] unless v.to_s =~ opts[:with] end end |
.validates_length_of(*atts) ⇒ Object
Validates the length of an attribute.
Possible Options:
-
:allow_blank - Whether to skip the validation if the value is blank (default: false)
-
:allow_nil - Whether to skip the validation if the value is nil (default: false)
-
:if - A symbol (indicating an instance_method) or proc (which is instance_evaled) skipping this validation if it returns nil or false.
-
:is - The exact size required for the value to be valid (no default)
-
:maximum - The maximum size allowed for the value (no default)
-
:message - The message to use (no default, overrides :too_long, :too_short, and :wrong_length options if present)
-
:minimum - The minimum size allowed for the value (no default)
-
:tag - The tag to use for this validation (default: :length)
-
:too_long - The message to use use if it the value is too long (default: ‘is too long’)
-
:too_short - The message to use use if it the value is too short (default: ‘is too short’)
-
:with - The array/range that must include the size of the value for it to be valid (no default)
-
:wrong_length - The message to use use if it the value is not valid (default: ‘is the wrong length’)
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 258 259 260 261 |
# File 'lib/sequel_model/validations.rb', line 233 def self.validates_length_of(*atts) opts = { :too_long => 'is too long', :too_short => 'is too short', :wrong_length => 'is the wrong length' }.merge!(atts.) tag = if opts[:tag] opts[:tag] else ([:length] + [:maximum, :minimum, :is, :within].reject{|x| !opts.include?(x)}).join('-').to_sym end atts << {:if=>opts[:if], :tag=>tag} validates_each(*atts) do |o, a, v| next if (v.nil? && opts[:allow_nil]) || (v.blank? && opts[:allow_blank]) if m = opts[:maximum] o.errors[a] << (opts[:message] || opts[:too_long]) unless v && v.size <= m end if m = opts[:minimum] o.errors[a] << (opts[:message] || opts[:too_short]) unless v && v.size >= m end if i = opts[:is] o.errors[a] << (opts[:message] || opts[:wrong_length]) unless v && v.size == i end if w = opts[:within] o.errors[a] << (opts[:message] || opts[:wrong_length]) unless v && w.include?(v.size) end end end |
.validates_numericality_of(*atts) ⇒ Object
Validates whether an attribute is a number.
Possible Options:
-
:allow_blank - Whether to skip the validation if the value is blank (default: false)
-
:allow_nil - Whether to skip the validation if the value is nil (default: false)
-
:if - A symbol (indicating an instance_method) or proc (which is instance_evaled) skipping this validation if it returns nil or false.
-
:message - The message to use (default: ‘is not a number’)
-
:tag - The tag to use for this validation (default: :numericality)
-
:only_integer - Whether only integers are valid values (default: false)
273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 |
# File 'lib/sequel_model/validations.rb', line 273 def self.validates_numericality_of(*atts) opts = { :message => 'is not a number', }.merge!(atts.) atts << {:if=>opts[:if], :tag=>opts[:tag]||:numericality} validates_each(*atts) do |o, a, v| next if (v.nil? && opts[:allow_nil]) || (v.blank? && opts[:allow_blank]) begin if opts[:only_integer] Kernel.Integer(v.to_s) else Kernel.Float(v.to_s) end rescue o.errors[a] << opts[:message] end end end |
.validates_presence_of(*atts) ⇒ Object
Validates the presence of an attribute. Requires the value not be blank, with false considered present instead of absent.
Possible Options:
-
:if - A symbol (indicating an instance_method) or proc (which is instance_evaled) skipping this validation if it returns nil or false.
-
:message - The message to use (default: ‘is not present’)
-
:tag - The tag to use for this validation (default: :presence)
301 302 303 304 305 306 307 308 309 310 |
# File 'lib/sequel_model/validations.rb', line 301 def self.validates_presence_of(*atts) opts = { :message => 'is not present', }.merge!(atts.) atts << {:if=>opts[:if], :tag=>opts[:tag]||:presence} validates_each(*atts) do |o, a, v| o.errors[a] << opts[:message] if v.blank? && v != false end end |
.validates_uniqueness_of(*atts) ⇒ Object
Validates only if the fields in the model (specified by atts) are unique in the database. Pass an array of fields instead of multiple fields to specify that the combination of fields must be unique, instead of that each field should have a unique value.
You should also add a unique index in the database, as this suffers from a fairly obvious race condition.
Possible Options:
-
:allow_nil - Whether to skip the validation if the value(s) is/are nil (default: false)
-
:if - A symbol (indicating an instance_method) or proc (which is instance_evaled) skipping this validation if it returns nil or false.
-
:message - The message to use (default: ‘is already taken’)
-
:tag - The tag to use for this validation (default: :uniqueness)
326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 |
# File 'lib/sequel_model/validations.rb', line 326 def self.validates_uniqueness_of(*atts) opts = { :message => 'is already taken', }.merge!(atts.) atts << {:if=>opts[:if], :tag=>opts[:tag]||:uniqueness} validates_each(*atts) do |o, a, v| error_field = a a = Array(a) v = Array(v) next unless v.any? or opts[:allow_nil] == false ds = o.class.filter(a.zip(v)) num_dups = ds.count allow = if num_dups == 0 # No unique value in the database true elsif num_dups > 1 # Multiple "unique" values in the database!! # Someone didn't add a unique index false elsif o.new? # New record, but unique value already exists in the database false elsif ds.first === o # Unique value exists in database, but for the same record, so the update won't cause a duplicate record true else false end o.errors[error_field] << opts[:message] unless allow end end |
Instance Method Details
#==(obj) ⇒ Object Also known as: eql?
Compares model instances by values.
59 60 61 |
# File 'lib/sequel_model/record.rb', line 59 def ==(obj) (obj.class == model) && (obj.values == @values) end |
#===(obj) ⇒ Object
If pk is not nil, true only if the objects have the same class and pk. If pk is nil, false.
66 67 68 |
# File 'lib/sequel_model/record.rb', line 66 def ===(obj) pk.nil? ? false : (obj.class == model) && (obj.pk == pk) end |
#[](column) ⇒ Object
Returns value of the column’s attribute.
41 42 43 |
# File 'lib/sequel_model/record.rb', line 41 def [](column) @values[column] end |
#[]=(column, value) ⇒ Object
Sets value of the column’s attribute and marks the column as changed. If the column already has the same value, this is a no-op.
47 48 49 50 51 52 53 54 55 56 |
# File 'lib/sequel_model/record.rb', line 47 def []=(column, value) # If it is new, it doesn't have a value yet, so we should # definitely set the new value. # If the column isn't in @values, we can't assume it is # NULL in the database, so assume it has changed. if new? || !@values.include?(column) || value != @values[column] changed_columns << column unless changed_columns.include?(column) @values[column] = typecast_value(column, value) end end |
#associations ⇒ Object
The current cached associations. A hash with the keys being the association name symbols and the values being the associated object or nil (many_to_one), or the array of associated objects (*_to_many).
79 80 81 |
# File 'lib/sequel_model/record.rb', line 79 def associations @associations ||= {} end |
#cache_key ⇒ Object
Return a key unique to the underlying record for caching, based on the primary key value(s) for the object. If the model does not have a primary key, raise an Error.
64 65 66 67 68 69 70 71 72 73 |
# File 'lib/sequel_model/caching.rb', line 64 def cache_key raise(Error, "No primary key is associated with this model") unless key = primary_key pk = case key when Array key.collect{|k| @values[k]} else @values[key] || (raise Error, 'no primary key for this record') end model.send(:cache_key, pk) end |
#changed_columns ⇒ Object
The columns that have been updated. This isn’t completely accurate, see Model#[]=.
85 86 87 |
# File 'lib/sequel_model/record.rb', line 85 def changed_columns @changed_columns ||= [] end |
#delete ⇒ Object
Deletes and returns self. Does not run destroy hooks. Look into using destroy instead.
91 92 93 94 95 |
# File 'lib/sequel_model/record.rb', line 91 def delete before_delete this.delete self end |
#destroy ⇒ Object
Like delete but runs hooks before and after delete. If before_destroy returns false, returns false without deleting the object the the database. Otherwise, deletes the item from the database and returns self.
101 102 103 104 105 106 107 108 |
# File 'lib/sequel_model/record.rb', line 101 def destroy db.transaction do return save_failure(:destroy) if before_destroy == false delete after_destroy end self end |
#each(&block) ⇒ Object
Enumerates through all attributes.
Example:
Ticket.find(7).each { |k, v| puts "#{k} => #{v}" }
114 115 116 |
# File 'lib/sequel_model/record.rb', line 114 def each(&block) @values.each(&block) end |
#errors ⇒ Object
Returns the validation errors associated with the object.
380 381 382 |
# File 'lib/sequel_model/validations.rb', line 380 def errors @errors ||= Validation::Errors.new end |
#exists? ⇒ Boolean
Returns true when current instance exists, false otherwise.
119 120 121 |
# File 'lib/sequel_model/record.rb', line 119 def exists? this.count > 0 end |
#hash ⇒ Object
Unique for objects with the same class and pk (if pk is not nil), or the same class and values (if pk is nil).
125 126 127 |
# File 'lib/sequel_model/record.rb', line 125 def hash [model, pk.nil? ? @values.sort_by{|k,v| k.to_s} : pk].hash end |
#id ⇒ Object
Returns value for the :id attribute, even if the primary key is not id. To get the primary key value, use #pk.
131 132 133 |
# File 'lib/sequel_model/record.rb', line 131 def id @values[:id] end |
#inspect ⇒ Object
Returns a string representation of the model instance including the class name and values.
137 138 139 |
# File 'lib/sequel_model/record.rb', line 137 def inspect "#<#{model.name} @values=#{@values.inspect}>" end |
#keys ⇒ Object
Returns attribute names as an array of symbols.
142 143 144 |
# File 'lib/sequel_model/record.rb', line 142 def keys @values.keys end |
#new? ⇒ Boolean
Returns true if the current instance represents a new record.
147 148 149 |
# File 'lib/sequel_model/record.rb', line 147 def new? @new end |
#pk ⇒ Object
Returns the primary key value identifying the model instance. Raises an error if this model does not have a primary key. If the model has a composite primary key, returns an array of values.
154 155 156 157 158 159 160 161 162 |
# File 'lib/sequel_model/record.rb', line 154 def pk raise(Error, "No primary key is associated with this model") unless key = primary_key case key when Array key.collect{|k| @values[k]} else @values[key] end end |
#pk_hash ⇒ Object
Returns a hash identifying the model instance. It should be true that:
Model[model_instance.pk_hash] === model_instance
167 168 169 |
# File 'lib/sequel_model/record.rb', line 167 def pk_hash model.primary_key_hash(pk) end |
#refresh ⇒ Object Also known as: reload
Reloads attributes from database and returns self. Also clears all cached association information. Raises an Error if the record no longer exists in the database.
174 175 176 177 178 179 |
# File 'lib/sequel_model/record.rb', line 174 def refresh @values = this.first || raise(Error, "Record not found") changed_columns.clear associations.clear self end |
#save(*columns) ⇒ Object
Creates or updates the record, after making sure the record is valid. If the record is not valid, or before_save, before_create (if new?), or before_update (if !new?) return false, returns nil unless raise_on_save_failure is true (if it is true, it raises an error). Otherwise, returns self. You can provide an optional list of columns to update, in which case it only updates those columns.
189 190 191 192 |
# File 'lib/sequel_model/record.rb', line 189 def save(*columns) return save_failure(:save) unless valid? save!(*columns) end |
#save!(*columns) ⇒ Object
Creates or updates the record, without attempting to validate it first. You can provide an optional list of columns to update, in which case it only updates those columns. If before_save, before_create (if new?), or before_update (if !new?) return false, returns nil unless raise_on_save_failure is true (if it is true, it raises an error). Otherwise, returns self.
200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 |
# File 'lib/sequel_model/record.rb', line 200 def save!(*columns) opts = columns. return save_failure(:save) if before_save == false if @new return save_failure(:create) if before_create == false ds = model.dataset if ds.respond_to?(:insert_select) and h = ds.insert_select(@values) @values = h @this = nil else iid = ds.insert(@values) # if we have a regular primary key and it's not set in @values, # we assume it's the last inserted id if (pk = primary_key) && !(Array === pk) && !@values[pk] @values[pk] = iid end if pk @this = nil # remove memoized this dataset refresh end end @new = false after_create else return save_failure(:update) if before_update == false if columns.empty? vals = opts[:changed] ? @values.reject{|k,v| !changed_columns.include?(k)} : @values this.update(vals) changed_columns.clear else # update only the specified columns this.update(@values.reject{|k, v| !columns.include?(k)}) changed_columns.reject!{|c| columns.include?(c)} end after_update end after_save self end |
#save_changes ⇒ Object
Saves only changed columns or does nothing if no columns are marked as chanaged. If no columns have been changed, returns nil. If unable to save, returns false unless raise_on_save_failure is true.
242 243 244 |
# File 'lib/sequel_model/record.rb', line 242 def save_changes save(:changed=>true) || false unless changed_columns.empty? end |
#set(hash) ⇒ Object Also known as: set_with_params
Updates the instance with the supplied values with support for virtual attributes, raising an exception if a value is used that doesn’t have a setter method (or ignoring it if strict_param_setting = false). Does not save the record.
If no columns have been set for this model (very unlikely), assume symbol keys are valid column names, and assign the column value based on that.
253 254 255 |
# File 'lib/sequel_model/record.rb', line 253 def set(hash) set_restricted(hash, nil, nil) end |
#set_all(hash) ⇒ Object
Set all values using the entries in the hash, ignoring any setting of allowed_columns or restricted columns in the model.
260 261 262 |
# File 'lib/sequel_model/record.rb', line 260 def set_all(hash) set_restricted(hash, false, false) end |
#set_except(hash, *except) ⇒ Object
Set all values using the entries in the hash, except for the keys given in except.
266 267 268 |
# File 'lib/sequel_model/record.rb', line 266 def set_except(hash, *except) set_restricted(hash, false, except.flatten) end |
#set_only(hash, *only) ⇒ Object
Set the values using the entries in the hash, only if the key is included in only.
272 273 274 |
# File 'lib/sequel_model/record.rb', line 272 def set_only(hash, *only) set_restricted(hash, only.flatten, false) end |
#set_values(values) ⇒ Object
Sets the value attributes without saving the record. Returns the values changed. Raises an error if the keys are not symbols or strings or a string key was passed that was not a valid column. This is a low level method that does not respect virtual attributes. It should probably be avoided. Look into using set instead.
281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 |
# File 'lib/sequel_model/record.rb', line 281 def set_values(values) s = str_columns vals = values.inject({}) do |m, kv| k, v = kv k = case k when Symbol k when String # Prevent denial of service via memory exhaustion by only # calling to_sym if the symbol already exists. raise(Error, "all string keys must be a valid columns") unless s.include?(k) k.to_sym else raise(Error, "Only symbols and strings allows as keys") end m[k] = v m end vals.each {|k, v| @values[k] = v} vals end |
#this ⇒ Object
Returns (naked) dataset that should return only this instance.
304 305 306 |
# File 'lib/sequel_model/record.rb', line 304 def this @this ||= dataset.filter(pk_hash).limit(1).naked end |
#update(hash) ⇒ Object Also known as: update_with_params
Runs set with the passed hash and runs save_changes (which runs any callback methods).
309 310 311 |
# File 'lib/sequel_model/record.rb', line 309 def update(hash) update_restricted(hash, nil, nil) end |
#update_all(hash) ⇒ Object
Update all values using the entries in the hash, ignoring any setting of allowed_columns or restricted columns in the model.
316 317 318 |
# File 'lib/sequel_model/record.rb', line 316 def update_all(hash) update_restricted(hash, false, false) end |
#update_except(hash, *except) ⇒ Object
Update all values using the entries in the hash, except for the keys given in except.
322 323 324 |
# File 'lib/sequel_model/record.rb', line 322 def update_except(hash, *except) update_restricted(hash, false, except.flatten) end |
#update_only(hash, *only) ⇒ Object
Update the values using the entries in the hash, only if the key is included in only.
328 329 330 |
# File 'lib/sequel_model/record.rb', line 328 def update_only(hash, *only) update_restricted(hash, only.flatten, false) end |
#update_values(values) ⇒ Object
Sets the values attributes with set_values and then updates the record in the database using those values. This is a low level method that does not run the usual save callbacks. It should probably be avoided. Look into using update_with_params instead.
336 337 338 339 |
# File 'lib/sequel_model/record.rb', line 336 def update_values(values) before_update_values this.update(set_values(values)) end |
#valid? ⇒ Boolean
Validates the object and returns true if no errors are reported.
394 395 396 397 |
# File 'lib/sequel_model/validations.rb', line 394 def valid? return false if validate == false errors.empty? end |
#validate ⇒ Object
Validates the object.
385 386 387 388 389 390 391 |
# File 'lib/sequel_model/validations.rb', line 385 def validate errors.clear return false if before_validation == false self.class.validate(self) after_validation nil end |