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.
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.
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
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
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
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
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.
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
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
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
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
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
Sequel supports logging of all database queries by allowing multiple loggers for each database:
DB.loggers << Logger.new($stdout)
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
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.
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.
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.where('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.where('name LIKE ?', 'A%')
This is because LIKE is case sensitive on PostgreSQL, but case insensitive on MySQL. With Sequel, you would do:
Album.where(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']))
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
MissingSequel 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].as(:artist)]}.first # SELECT albums.id, albums.name, artists.name AS artist album.artist # Error! album[:artist] # Works
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:
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 +:reload=>true+ to the association method.
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)
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.
These options are shared by more than one ActiveRecord association.
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
or one_through_one
association, or the many_through_many
plugin
:touch
The touch
plugin
:autosave
A before_save
or after_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
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
.
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.
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.
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('postgres://...') Album.db = BACKUP_DB
If you want a specific dataset in that database for a model, setup the model with a specific dataset:
class Album < Sequel::Model(BACKUP_DB[:albums]); end
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(: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:
filter, where
order
group
limit
offset
join, left_join, etc. # many other join methods
eager, eager_graph # eager does preloading, eager_graph does JOINs
select
from
# No Sequel equivalent
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
none
If you want to return an empty dataset, but still preserve chaining, you
can use the null_dataset
extension:
DB.extension(:null_dataset) class User < Sequel::Model def self.nullify dataset.nullify end end user = User.create(name: 'John Doe') User.nullify.where(name: 'John Doe').all # => []
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.
Note that Sequel uses symbols almost everywhere to represent columns, while ActiveRecord often returns columns as strings.
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
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=>Sequel.+(:counter_name,
1), :other_counter=>Sequel.-(:other_counter, 1))
uncached
No equivalent
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)
Note that Sequel uses symbols almost everywhere to represent columns, while ActiveRecord often returns columns as strings.
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 the caching
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 the active_model
plugin
touch
touch
, if using the touch
plugin
valid?
valid?
Notes, Workarounds
after_validation_on_create
, after_validation_on_update
Use after_validation
and if new?
or unless
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 the blank
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
and if new?
or unless
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
or after_save
hook or the
instance_hooks
plugin
readonly!
No equivalent
readonly?
No equivalent
rollback_active_record_state!
No equivalent
with_transaction_returning_status
No equivalent