Skip to content

Latest commit

 

History

History
927 lines (612 loc) · 39 KB

active_record.rdoc

File metadata and controls

927 lines (612 loc) · 39 KB

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.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']))

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].as(: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

Sequel

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.

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 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

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('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:

: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

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.

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=>Sequel.+(:counter_name, 1), :other_counter=>Sequel.-(: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 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?

Instance Methods without an Equivalent

ActiveRecord Method

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