Sequel for ActiveRecord Users
This guide is aimed at helping ActiveRecord users transition to Sequel. It assumes the user is familiar with ActiveRecord 2, but if you are familiar with a newer ActiveRecord version, the transition should be even easier.
Introduction
Both Sequel and ActiveRecord use the active record pattern of database access, where model instances are objects that wrap a row in a database table or view, encapsulating the database access, and adding domain logic on that data. Just like ActiveRecord, Sequel supports both associations and inheritance, though Sequel does so in a more flexible manner than ActiveRecord.
Let’s quickly run through the ActiveRecord README and show how it applies to Sequel.
Automatic Mapping
Just like ActiveRecord, Sequel maps classes to tables and automatically creates accessor methods for the columns in the table, so if you have an albums table with a primary key named “id” and a string/varchar column named “name”, the minimal model class is:
class Album < Sequel::Model end
Sequel will autogenerate the column accessors, so you can do:
album = Album.new album.name = 'RF'
If the table name for the class doesn’t match the default one Sequel will choose, you can specify it manually:
class Album < Sequel::Model(:records) end
Associations
Sequel supports most of the same association types as ActiveRecord, but it uses names that reflect the database relationships instead of ones that imply ownership:
class Album < Sequel::Model many_to_one :artist one_to_many :tracks many_to_many :tags end
Compositions
Sequel’s composition
plugin allows you to easily create
accessor methods that are composed of one or more of the database’s
columns, similar to ActiveRecord’s composed_of
:
class Artist < Sequel::Model plugin :composition composition :address, :mapping=>[:street, :city, :state, :zip] end
Validations
Sequel’s validation_class_methods
plugin is modeled directly
on ActiveRecord’s validations, but the recommended approach is to use the
validation_helpers
plugin inside a validate
instance method:
class Album < Sequel::Model plugin :validation_helpers def validate super validates_presence [:name, :copies_sold] validates_unique [:name, :artist_id] end end
Hooks/Callbacks
Sequel’s hook_class_methods
plugin is modeled directly on
ActiveRecord’s callbacks, but the recommended approach is to define your
hooks/callbacks as instance methods:
class Album < Sequel::Model def before_create self.copies_sold ||= 0 super end def after_update super AuditLog.create(:log=>"Updated Album #{id}") end end
Observers can be implemented completely by hooks, so Sequel doesn’t offer a separate observer class.
Inheritance
Sequel supports both single table inheritance and class table inheritance using plugins:
class Employee < Sequel::Model plugin :single_table_inheritance, :class_name_column # or plugin :class_table_inheritance end class Staff < Employee end class Manager < Employee end class Executive < Manager end
Transactions
Sequel supports transactions via the Database object (we recommend using the DB constant for single database applications):
DB.transaction do album.artist.num_albums -= 1 album.artist.save album.delete end
For model classes, you can always access the database via db
:
Album.db.transaction do album.artist.num_albums -= 1 album.artist.save album.delete end
Reflection
Just like ActiveRecord, Sequel has full reflection support for columns, associations, and many other things:
Album.columns # => [:id, :name, :artist_id, :copies_sold] reflection = Album.association_reflection(:artist) reflection[:type] == :many_to_one
Direct Manipulation
Just like ActiveRecord, Sequel
doesn’t use sessions, it lets you modify objects and have them be saved
inside the call to save
:
album = Album[1234] # modify album album.save
Database Abstraction
Sequel supports far more database abstractions than ActiveRecord, and setting up the database connection is easy:
DB = Sequel.sqlite # memory database DB = Sequel.connect('postgres://user:pass@host/database') # connection string DB = Sequel.connect(:adapter=>'postgres', :user=>'?', :password=>'?', :host=>'?', :database=>'?') # option hash
Logging
Sequel supports logging of all database queries by allowing multiple loggers for each database:
DB.loggers << Logger.new($stdout)
Migrations
Sequel supports migrations and has a migrator similar to ActiveRecord:
Sequel.migration do change do create_table(:albums) do primary_key :id String :name end end end
Differences
By now, you should have the idea that Sequel supports most things that ActiveRecord supports. The rest of this guide is going to go over how Sequel differs from ActiveRecord in terms of operation.
Method Chaining
Unlike ActiveRecord 2 (and similar to ActiveRecord 3+), Sequel uses method chains on datasets for retrieving objects, so instead of:
Album.find(:all, :conditions=>['name > ? AND artist_id = ?', 'RF', 1], :order=>'copies_sold', :select=>'id, name')
Sequel uses:
Album.where{name > 'RF'}.where(:artist_id=>1).order(:copies_sold). select(:id, :name).all
Note that the records aren’t retrieved until all
is called.
ActiveRecord 3 adopts this method chaining approach, so if you are familiar with it, it should be even easier to transition to Sequel.
No Need for SQL String Fragments
Like the example above, most ActiveRecord code uses SQL string fragments. With Sequel, you rarely need to. Sequel’s DSL allows you to create complex queries without ever specifying SQL string fragments (called literal strings in Sequel).
If you want to use SQL string fragments, Sequel makes it easy by using the
Sequel.lit
method:
Album.select(Sequel.lit('id, name'))
This usage is not encouraged, though. The recommended way is to use symbols to represent the columns:
Album.select(:id, :name)
Sequel keeps datasets in an abstract format, allowing for powerful capabilities. For example, let's say you wanted to join to the artists table. Sequel can automatically qualify all references in the current dataset, so that it can be safely joined:
Album.select(:id, :name).qualify.join(:artists, :id=>:artist_id)
This isn’t possible when you use an SQL string fragment. Another case where using an SQL string fragment hurts you is when the SQL syntax cannot handle all cases:
Album.filter('id NOT IN ?', ids_array)
That will work fine if ids_array
is not empty, but will not
work correctly if it is empty. With Sequel, you do:
Album.exclude(:id=>ids_array)
That will handle cases where ids_array
is empty correctly.
A third reason to not use SQL string fragments is database independence. For example, if you want a case insensitive search that works on both PostgreSQL and MySQL, the following won’t work:
Album.filter('name LIKE ?', 'A%')
This is because LIKE is case sensitive on PostgreSQL, but case insensitive on MySQL. With Sequel, you would do:
Album.filter(Sequel.ilike(:name, 'A%'))
This will do a case insensitive search on both databases. If you want a
case sensitive search on both, you can use like
instead of
ilike
.
String concatenation is a similar area, where MySQL and PostgreSQL handle things differently. With Sequel, the same code can work on both databases:
Album.select(Sequel.join([:name, ' - Name']))
Flexible Overriding
Unlike ActiveRecord 2, which forces you to alias methods if you want to override them, with Sequel you just override the methods and call super:
class Sequel::Model def after_update super AuditLog.create(:log=>"#{model.name} with primary key #{pk} updated") end end
With that code, you have enabled auditing for all model object updates.
Let’s say you want to override accessor methods. In Sequel, instead of using
read_attribute
and write_attribute
, you can just
call super:
class Track < Sequel::Model # database holds length in integer seconds, # but you want it in minutes as a float def length=(minutes) super((minutes*60).to_i) end def length super/60.0 end end
You can override almost all model class or instance methods this way, just
remember to call super
.
method_missing
Missing
Sequel does not use
method_missing
unless it's required that the object respond to
potentially any method. Neither Sequel::Model
nor
Sequel::Dataset
nor Sequel::Database
implement
method_missing
at either a class or instance level. So if you
call methods
, you can see which methods are available, and if
they aren't listed, then the object won't respond to them. Among other
things, this means Sequel does not
support dynamic finders. So instead of:
Album.find_or_create_by_name("RF")
You just use:
Album.find_or_create(:name=>"RF")
At the instance level, this means that if you select columns that aren’t in
the models table, you need to use Model#[]
to access them:
album = Album.join(:artist, :id=>:artist_id). select(:albums__id, :albums__name, :artists__name___artist).first # SELECT albums.id, albums.name, artists.name AS artist album.artist # Error! album[:artist] # Works
Associations
Sequel associations are similar to ActiveRecord associations in some ways, and much different in others. Sequel provides four association creation methods that map to ActiveRecord's associations:
- ActiveRecord
belongs_to
-
many_to_one
has_one
-
one_to_one
has_many
-
one_to_many
has_and_belongs_to_many
-
many_to_many
Like ActiveRecord, when you create an association in Sequel, it creates an instance method
with the same name that returns either the matching object or nil for the
*_to_one
associations, or an array of matching objects for the
*_to_many
associations.
Updating *_to_many
associations is very different, however.
ActiveRecord makes the association method returns an association proxy that
looks like an array, but has a bunch of added methods to manipulate the
associated records. Sequel uses
instance methods on the object instead of a proxy to modify the
association. Here’s a basic example:
Artist.one_to_many :albums Album.many_to_one :artist artist = Artist[1] album = Album[1] artist.albums # array of albums album.artist # Artist instance or nil artist.add_album(album) # associate album to artist artist.remove_album(album) # disassociate album from artist artist.remove_all_albums # disassociate all albums from artist
Sequel doesn't have a
has_many :through
association, instead you can use a
many_to_many
association in most cases. Sequel ships with a
many_through_many
plugin that allows you to set up a many to
many relationship through an arbitrary number of join tables.
Sequel doesn't come with support
for polymorphic associations. Using polymorphic associations is generally
bad from a database design perspective, as it violates referential
integrity. If you have an old database and must have polymorphic
associations, there is an external sequel_polymorphic
plugin
that can handle them, just by using the standard association options
provided by Sequel.
Sequel doesn't directly support
creating a bunch of associated objects and delaying saving them to the
database until the main object is saved, like you can with the
association.build
methods in ActiveRecord. You can use
+before_save or after_save
hooks, or the
nested_attributes
or instance_hooks
plugins to
get similar support.
Sequel supports the same basic
association hooks/callbacks as ActiveRecord. It also supports
:after_load
, which is run after the associated objects are
loaded. For *_to_one
associations, it supports
before_set
and after_set
hooks, since a setter
method is used instead of an add/remove method pair.
If you pass a block to an association method, it’s used to return a modified dataset used for the association, instead of to create an association extension:
Artist.one_to_many :gold_albums, :class=>:Album do |ds| ds.where{copies_sold > 500000} end
If you want to create an association extension, you can use the
:extend
association option with a module, which ActiveRecord
also supports. In Sequel, the
extensions are applied to the association dataset, not to the array of
associated objects. You can access the association dataset using the
association_dataset
method:
artist.albums_dataset album.artist_dataset
Association datasets are just like any other Sequel dataset, in that you can filter them and manipulate them further:
gold_albums = artist.albums_dataset.where{copies_sold > 500000}.order(:name).all
Sequel caches associated objects
similarly to ActiveRecord, and you can skip the cache by passing
true
to the association method, just like ActiveRecord.
Eager Loading
ActiveRecord 2 tries to guess whether to use preloading or JOINs for eager
loading by scanning the SQL string fragments you provide for table names.
This is error prone and Sequel
avoids it by giving you separate methods. In Sequel, eager
is used for
preloading and eager_graph
is used for JOINs. Both have the
same API:
Artist.eager(:albums=>[:tags, :tracks]) Album.eager_graph(:artist, :tracks)
With either way of eager loading, you must call all
to
retrieve all records at once. You cannot use each
,
map
, or one of the other Enumerable methods. Just like
each
, all
takes a block that iterates over the
records:
Artist.eager(:albums=>[:tags, :tracks]).each{|a| ...} # No cookie Artist.eager(:albums=>[:tags, :tracks]).all{|a| ...} # Cookie
Like ActiveRecord, Sequel supports cascading of eager loading for both methods of eager loading.
Unlike ActiveRecord, Sequel allows
you to eager load custom associations using the :eager_loader
and :eager_grapher
association options. See the Advanced Associations guide for
more details.
Table aliasing when eager loading via eager_graph
is different
in Sequel than ActiveRecord. Sequel will always attempt to use the
association name, not the table name, for any associations. If the
association name has already been used, Sequel will append _N to it, where N
starts at 0 and increases by 1. For example, for a self referential
association:
class Node < Sequel::Model many_to_one :parent, :class=>self one_to_many :children, :class=>self, :key=>:parent_id end Node.eager_graph(:parent=>:parent, :children=>{:children=>:children}).all # SELECT nodes.id, nodes.parent_id, -- main table # parent.id AS parent_id_0, parent.parent_id AS parent_parent_id, -- parent # parent_0.id AS parent_0_id, parent_0.parent_id AS parent_0_parent_id, -- grandparent # children.id AS children_id, children.parent_id AS children_parent_id, -- children # children_0.id AS children_0_id, children_0.parent_id AS children_0_parent_id, -- grandchildren # children_1.id AS children_1_id, children_1.parent_id AS children_1_parent_id -- great grandchidren # FROM nodes -- main table # LEFT OUTER JOIN nodes AS parent ON (parent.id = nodes.parent_id) -- parent # LEFT OUTER JOIN nodes AS parent_0 ON (parent_0.id = parent.parent_id) -- grandparent # LEFT OUTER JOIN nodes AS children ON (children.parent_id = nodes.id) -- children # LEFT OUTER JOIN nodes AS children_0 ON (children_0.parent_id = children.id) -- grandchildren # LEFT OUTER JOIN nodes AS children_1 ON (children_1.parent_id = children_0.id) -- great grandchildren
You can specify aliases on a per join basis, too:
Node.eager_graph(:parent=>Sequel.as(:parent, :grandparent), :children=>{Sequel.as(:children, :grandchildren)=>Sequel.as(:children, :great_grandchildren)}).all # SELECT nodes.id, nodes.parent_id, # parent.id AS parent_id_0, parent.parent_id AS parent_parent_id, # grandparent.id AS grandparent_id, grandparent.parent_id AS grandparent_parent_id, # children.id AS children_id, children.parent_id AS children_parent_id, # grandchildren.id AS grandchildren_id, grandchildren.parent_id AS grandchildren_parent_id, # great_grandchildren.id AS great_grandchildren_id, great_grandchildren.parent_id AS great_grandchildren_parent_id # FROM nodes # LEFT OUTER JOIN nodes AS parent ON (parent.id = nodes.parent_id) # LEFT OUTER JOIN nodes AS grandparent ON (grandparent.id = parent.parent_id) # LEFT OUTER JOIN nodes AS children ON (children.parent_id = nodes.id) # LEFT OUTER JOIN nodes AS grandchildren ON (grandchildren.parent_id = children.id) # LEFT OUTER JOIN nodes AS great_grandchildren ON (great_grandchildren.parent_id = grandchildren.id)
Options
Sequel supports many more association options than ActiveRecord, but here's a mapping of ActiveRecord association options to Sequel association options. Note that when you specify columns in Sequel, you use symbols, not strings. Where ActiveRecord would use an SQL string fragment with embedded commas for multiple columns, Sequel would use an array of column symbols.
Shared options
These options are shared by more than one ActiveRecord association.
- ActiveRecord option
-
Sequel option
:class_name
-
:class
:conditions
-
:conditions
:select
-
:select
:order
-
:order
:extend
-
:extend
:limit
-
:limit
:offset
-
:limit
with an array with the second element being the offset :uniq
-
:uniq
:validate
-
:validate
:dependent
-
The
associations_dependencies
plugin :polymorphic
,:as
,:source_type
-
The
sequel_polymorphic
external plugin :include
-
:eager
,:eager_graph
:readonly
-
No equivalent, the Sequel
:read_only
option just means the modification methods are not created (it makes the association read only, not records retrieved through the association) :through
,:source
-
Use a
many_to_many
association, or themany_through_many
plugin :touch
-
The
touch
plugin :autosave
-
A
before_save
orafter_save
hook :finder_sql
-
:dataset
to set a custom dataset :counter_sql
-
No direct equivalent, but a count on the dataset will use the custom dataset specified by
:dataset
:group
-
Use the association block to add the group to the dataset
:having
-
Use the association block to add the having to the dataset
belongs_to
belongs_to
option-
many_to_one
option :foreign_key
-
:key
:primary_key
-
:primary_key
:counter_cache
-
No equivalent
has_one
, has_many
has_one
,has_many
option-
one_to_one
,one_to_many
option :foreign_key
-
:key
has_and_belongs_to_many
has_and_belongs_to_many
option-
many_to_many
option :foreign_key
-
:left_key
:association_foreign_key
-
:right_key
:join_table
-
:join_table
:delete_sql
-
:remover
:insert_sql
-
:adder
Validation Errors
If there are errors when validating an object in Sequel, they are stored in a
Sequel::Model::Errors
instance. It’s mostly similar to
ActiveRecord::Errors
, so this section will just go over the
differences.
Sequel::Model::Errors
is a hash subclass where keys are
usually column symbols (not required), and values are arrays of error
messages. So if you have two error messages on the same column,
each
will only yield once, not twice.
The add_on_blank
, add_on_empty
,
add_to_base
, each_full
,
generate_message
, invalid?
, on_base
,
and to_xml
methods don’t exist. []
should not be
used directly, instead you should use on
.
You can think of Sequel::Model::Errors
as a subset of
ActiveRecord::Errors
if you stick to on
,
add
, and full_messages
.
Sequel Configuration Flags
Unlike ActiveRecord, Sequel’s behavior depends on how you configure it. In Sequel, you can set flags at the global, class, and instance level that change the behavior of Sequel. Here’s a brief description of the flags:
raise_on_save_failure
-
Whether to raise an error instead of returning nil on a failure to save/create/save_changes/etc due to a validation failure or a before_* hook returning false. By default, an error is raised, when this is set to false, nil is returned instead.
raise_on_typecast_failure
-
Whether to raise an error when unable to typecast data for a column (default: true). This should be set to false if you want to use validations to display nice error messages to the user (e.g. most web applications). You can use the
validates_schema_types
validation in connection with this option to check for typecast failures. require_modification
-
Whether to raise an error if an UPDATE or DELETE query related to a model instance does not modify exactly 1 row. If set to false, Sequel will not check the number of rows modified (default: true if the database supports it).
strict_param_setting
-
Whether new/set/update and their variants should raise an error if an invalid key is used. A key is invalid if no setter method exists for that key or the access to the setter method is restricted (e.g. due to it being a primary key field). If set to false, silently skip any key where the setter method doesn’t exist or access to it is restricted.
typecast_empty_string_to_nil
-
Whether to typecast the empty string (”) to nil for columns that are not string or blob. In most cases the empty string would be the way to specify a NULL SQL value in string form (nil.to_s == ”), and an empty string would not usually be typecast correctly for other types, so the default is true.
typecast_on_assignment
-
Whether to typecast attribute values on assignment (default: true). If set to false, no typecasting is done, so it will be left up to the database to typecast the value correctly.
use_transactions
-
Whether to use a transaction by default when saving/deleting records (default: true). If you are sending database queries in before or after hooks, you shouldn’t change the default setting without a good reason.
ActiveRecord Method to Sequel Method Mapping
This part of the guide will list Sequel equivalents for ActiveRecord methods, hopefully allowing you to convert your existing ActiveRecord code to Sequel code more easily.
Class Methods with Significantly Different Behavior
abstract_class
, abstract_class=
, abstract_class?
With Sequel, these methods don’t
exist because it doesn’t default to using single table inheritance in
subclasses. ActiveRecord assumes that subclasses of Model classes use
single table inheritance, and you have to set abstract_class =
true
to use an abstract class. In Sequel, you must use the
single_table_inheritance
or
class_table_inheritance
plugin to configure inheritance in the
database.
all
In both Sequel and ActiveRecord,
calling all
will give you an array of all records. However,
while in ActiveRecord you pass options to all
to filter or
order the results, in Sequel you
call dataset methods to filter or order the results, and then end the
method chain with a call to all
to return the records.
column_names
Sequel uses symbols for columns, so
the columns
method returns an array of symbols. If you want
an array of strings:
Album.columns.map{|x| x.to_s}
columns
Sequel::Model.columns
returns an array of column name symbols.
The closest similar thing would be to get the database schema hash for each
column:
Album.columns.map{|x| Album.db_schema[x]}
composed_of
As mentioned earlier, Sequel uses
the composition
plugin for this:
class Artist < Sequel::Model plugin :composition composition :address, :mapping=>[:street, :city, :state, :zip] end
connected?
Sequel::Model
raises an exception if you haven't instantiated
a Sequel::Database
object before loading the model class.
However, if you want to test the connection to the database:
Sequel::Model.db.test_connection
Note that test_connection
will return true if a connection can
be made, but will probably raise an exception if it cannot be made.
connection
Sequel only uses connections for the minimum amount of time necessary, checking them out to do a query, and returning them as soon as the query finishes. If you do want direct access to the connection object:
Sequel::Model.db.synchronize do |connection| ... end
Note that the connection is yielded to the block, and the block ensures it is returned to the pool. Sequel doesn’t have a method that returns a connection, since that would check it out with no ability to ensure it is returned to the pool.
count_by_sql
You can call with_sql
to set the SQL to use, and the
single_value
to retrieve the result.
Album.with_sql("SELECT COUNT(*) ...").single_value
delete
, delete_all
You probably want to filter first, then call delete
:
Album.where(:id=>id).delete Album.where("artist_id = ?", 5).delete
If you really want to delete all rows in the table,call delete
on the Model’s dataset:
Album.dataset.delete
destroy
, destroy_all
Similar to delete
, you filter first, then
destroy
:
Album.where(:id=>id).destroy Album.where("artist_id = ?", 5).destroy
If you really want to destroy all rows in the table,call
destroy
on the Model’s dataset:
Album.dataset.destroy
establish_connection
If you want to use a specific Sequel::Database
object, you can
use db=
:
BACKUP_DB = Sequel.connect(...) Album.db = BACKUP_DB
If you want a specific dataset in that database, you can use
set_dataset
or dataset=
:
Album.set_dataset BACKUP_DB[:albums] Album.dataset = BACKUP_DB[:albums]
exists?
You need to filter the dataset first, then call empty?
and
invert the result:
!Album.where(:id=>1).empty?
find
ActiveRecord’s find
can be used for a lot of different things.
If you are trying to find a single object given a primary key:
Album[1]
Note that Sequel returns nil if no record is found, it doesn’t raise an exception. To raise an exception if no record is found:
Album.with_pk!(1)
If you want to find multiple objects using an array of primary keys:
Album.where(:id=>[1, 2, 3]).all
If you are using find(:first, ...)
, you use a method chain
instead of passing the options, and end it with first
:
Album.where(:artist_id=>1).order(:name).first
If you are using find(:last, ...)
, you need to specify an
order in Sequel, but the same
method chain approach is used, which you end with last
:
Album.where(:artist_id=>1).order(:name).last # You could also do: Album.where(:artist_id=>1).reverse_order(:name).first
If you are using find(:all, ...)
, you use a method chain
instead of passing the options, and end it with all
:
Album.where(:artist_id=>1).order(:name).all
Here’s a mapping of ActiveRecord find
options to
Sequel::Dataset
methods:
- :conditions
-
filter, where
- :order
-
order
- :group
-
group
- :limit
-
limit
- :offset
-
offset
- :joins
-
join, left_join, etc. # many other join methods
- :include
-
eager, eager_graph # eager does preloading, eager_graph does JOINs
- :select
-
select
- :from
-
from
- :read_only
-
# No Sequel equivalent
- :lock
-
for_update, lock_style
find_by_sql
Similar to count_by_sql
, you use with_sql
,
followed by all
:
Album.with_sql("SELECT * FROM albums WHERE ...").all
first
Just like with find(:first, ...)
, you use a method chain
instead of passing the options, and end it with first
:
Album.where(:artist_id=>1).order(:name).first
last
Just like with find(:last, ...)
, you use a method chain
instead of passing the options, make sure it includes an order, and end it
with last
:
Album.where(:artist_id=>1).order(:name).last
named_scope
For a pure filter, you can use subset
:
Album.subset(:debut, :position => 1) Album.subset(:gold){copies_sold > 500000}
For anything more complex, you can use dataset_module
:
Album.dataset_module do def by_artist(artist_id) where(:artist_id=>artist_id) end def by_release_date order(:release_date) end end
reset_column_information
If you want to completely reload the schema for the table:
Album.instance_variable_set(:@db_schema, nil) Album.send(:get_db_schema, true)
serialize
, seralized_attributes
Sequel ships with a
serialization
plugin that you can use.
class Album < Sequel::Model plugin :serialization, :json, :permissions end
For serialized_attributes
, you can use
serialization_map
, which is also a hash, but keys are column
symbols and values are callable objects used to serialize the values.
set_inheritance_column
This is something that must be specified when you are loading the
single_table_inheritance
plugin:
class Album < Sequel::Model plugin :single_table_inheritance, :column end
set_sequence_name
Sequel will usually auto discover the sequence to use. However, on Oracle this should be specified by making sure the model's dataset includes a sequence:
class Album < Sequel::Model(ORACLE_DB[:albums].sequence('albums_seq')) end
table_exists?
This is a Sequel::Database
method:
Album.db.table_exists?(Album.table_name)
With the schema
plugin, you can use it directly:
Album.plugin :schema Album.table_exists?
transaction
As mentioned earlier, transaction
is a database method in Sequel, which you can access via the
db
method:
Album.db.transaction{}
update
, update_all
Just like delete
and destroy
, you filter first,
then update
:
Album.where(:id=>id).update(:name=>'RF') Album.where("artist_id = ?", 5).update(:copies_sold=>0)
Likewise, to update all rows in the model:
Album.dataset.update(:name=>'RF')
Note that update
in that case will operate on a dataset, so it
won’t run model validations or hooks. If you want those run:
Album[id].update(:name=>'RF') Album.where("artist_id = ?", 5).all{|a| a.update(:copies_sold=>0)}
with_scope
Sequel works a little differently
than with_scope. Instead of using nested blocks, you just use a cleaner
method chain. with_scope
is often used as an around_filter or
similar construct, where in Sequel,
you would just need to assign to a dataset in a before filter, and use that
dataset in the action.
Class Methods with Roughly the Same Behavior
Note that Sequel uses symbols almost everywhere to represent columns, while ActiveRecord often returns columns as strings.
- ActiveRecord Method
-
Sequel Method
attr_accessible
-
set_allowed_columns
attr_protected
-
set_restricted_columns
average
-
avg
belongs_to
-
many_to_one
columns_hash
-
db_schema
count
-
count
changed
-
changed_columns
create
-
create
has_and_belongs_to_many
-
many_to_many
has_one
-
one_to_one
has_many
-
one_to_many
inheritance_column
-
sti_key
inspect
-
inspect
maximum
-
max
minimum
-
min
new
-
new
primary_key
-
primary_key
respond_to?
-
respond_to?
set_primary_key
-
set_primary_key
sum
-
sum
table_name
-
table_name
unscoped
-
unfiltered
Class Methods without an Equivalent
- ActiveRecord Method
-
Notes, Workarounds
accepts_nested_attributes_for
-
Use the
nested_attributes
plugin attr_readonly
-
Don’t update the columns (duh!), or add a before_update hook that deletes them from the values hash
attribute_method_suffix
-
No equivalent
alias_attribute_with_dirty
-
No equivalent
base_class
-
Not needed internally, you can probably use
sti_dataset.model
if you are using single table inheritance benchmark
-
Just use the
benchmark
library from ruby’s stdlib calculate
-
No direct equivalent, just build the query manually and execute it
cache
-
No equivalent
cache_attribute?
-
No equivalent
cache_attributes
-
No equivalent
cached_attributes
-
No equivalent
changed?
-
changed_columns.include?(column)
changes
-
No equivalent
clear_active_connections!
-
Sequel doesn't leak connections like ActiveRecord, so you don't need to worry about this
clear_reloadable_connections!
-
Sequel doesn't leak connections like ActiveRecord, so you don't need to worry about this
content_columns
-
Not needed internally, you can probably do
Album.columns.map{|x| x.to_s}.delete_if{|x| x == Album.primary_key || x =~ /_(id|count)\z/}
decrement_counter
-
Album.where(:id=>:id).update(:counter_name=>Sequel.-(:counter_name, 1))
define_attribute_methods
,define_read_methods
-
def_column_accessor(*columns)
, a private method descends_from_active_record?
-
Not needed internally, if using single table inheritance,
Album.sti_dataset.model == Album
find_each
,find_in_batches
-
Use the
pagination
extension generated_methods?
-
No equivalent
increment_counter
-
Album.where(:id=>:id).update(:counter_name=>Sequel.+(:counter_name, 1))
instance_method_already_implemented?
-
No equivalent, Sequel does not create column accessors that override other methods, it just skips them.
match_attribute_method?
-
No equivalent
readonly_attributes
-
No equivalent
remove_connection
-
Not necessary in Sequel. If you want to disconnect an existing connection:
Album.db.disconnect
require_mysql
-
A public method, really?
silence
-
No equivalent. Because the logger is handled at the
Sequel::Database
level, there is no thread-safe way to turn it off for specific blocks. scopes
-
No equivalent
sti_name
-
No equivalent.
update_counters
-
Album.where(:id=>:id).update(:counter_name=>:counter_name + 1, :other_counter=>:other_counter - 1)
uncached
-
No equivalent
Instance Methods with Significantly Different Behavior
attribute_names
keys
returns the columns as unsorted symbols, so:
album.keys.map{|x| x.to_s}.sort
becomes
Assuming the record already exists in the database:
gold_album = GoldAlbum[1] album = Album.load(gold_album.values)
If it is a new record:
gold_album = GoldAlbum.new(:name=>'a') album = Album.new album.send(:set_values, gold_album.values)
column_for_attribute
You can access this through the db_schema
hash:
album.db_schema[:column]
connection
Just like in the class method, you have to access it through the database:
album.db.synchronize do |connection| end
decrement
, increment
You can just modify the values hash directly:
album.values[:column] ||= 0 album.values[:column] -= 1 # or += 1 for increment
decrement!
, increment!
Assuming you want the full behavior of saving just one column without validating:
album.values[:column] ||= 0 album.values[:column] -= 1 # or += 1 for increment! album.save(:columns=>[:column], :validate=>false)
has_attribute?
You have to check the values hash:
album.values.has_key?(:column)
invalid?
You can use unless valid?
or !valid?
.
save
, save!
, save_with_validation
, save_with_validation!
Sequel defaults to raising
exceptions when save
fails, but this is configurable behavior
by setting the raise_on_save_failure
flag on the class or
instance:
album.raise_on_save_failure = true album.save # raise exception if failure album.raise_on_save_failure = false album.save # return nil if failure
You can pass the :validate=>false
option to not validate
the object when saving.
toggle
, toggle
No equivalent, but very easy to add:
album.column = !album.column
If you want to save just that column:
album.save(:columns=>[:column], :validate=>false)
transaction
Just like in the class, you can access the transaction method through the
db
:
album.db.transaction{}
update_attribute
To only set and save a specific column:
album.set(:column => value) album.save(:columns=>[:column], :validate=>false)
update_attributes
, update_attributes!
These would both use update
, but see the notes on the
raise_on_save_failure
flag:
album.update(:column1=>value1, :column2=>value2)
Instance Methods with Roughly the Same Behavior
Note that Sequel uses symbols almost everywhere to represent columns, while ActiveRecord often returns columns as strings.
- ActiveRecord Method
-
Sequel Method
==
-
===
,==
compares by all values, not just id []
-
[]
[]=
-
[]=
after_create
-
after_create
after_destroy
-
after_destroy
after_save
-
after_save
after_update
-
after_update
after_validation
-
after_validation
attributes
-
values
attributes=
-
set
before_create
-
before_create
before_destroy
-
before_destroy
before_save
-
before_save
before_update
-
before_update
before_validation
-
before_validation
cache_key
-
cache_key
, if using thecaching
plugin destroy
-
destroy
eql?
-
===
errors
-
errors
freeze
-
freeze
frozen?
-
frozen?
hash
-
hash
id
-
pk
inspect
-
inspect
lock!
-
lock!
new_record?
-
new?
reload_with_autosave_associations
-
reload
to_param
-
to_param
, if using theactive_model
plugin touch
-
touch
, if using thetouch
plugin valid?
-
valid?
Instance Methods without an Equivalent
- ActiveRecord Method
-
Notes, Workarounds
after_validation_on_create
,after_validation_on_update
-
Use
after_validation
andif new?
orunless new?
as_json
,from_json
,to_json
-
Use the
json_serializer
plugin from_xml
,to_xml
-
Use the
xml_serializer
plugin attribute_for_inspect
-
album[:column].inspect
attribute_present?
-
!album[:column].blank?
if using theblank
extension attributes_before_type_cast
-
Sequel typecasts at a low level, so model objects never see values before they are type cast
before_validation_on_create
,before_validation_on_update
-
Use
before_validation
andif new?
orunless new?
id=
-
Sequel doesn't have a special primary key setter method, but you can use:
album.send("#{Album.primary_key}=", value)
mark_for_destruction
,marked_for_destruction?
-
Use a
before_save
orafter_save
hook or theinstance_hooks
plugin readonly!
-
No equivalent
readonly?
-
No equivalent
rollback_active_record_state!
-
No equivalent
with_transaction_returning_status
-
No equivalent