Last Update: 2013-06-02 13:49:43 -0700

Sequel::Model Mass Assignment

Most Model methods that take a hash of attribute keys and values, including, Model.create, Model#set and Model#update are subject to Sequel's mass assignment rules. When you pass a hash to these methods, each key has an = appended to it (the setter method), and if the setter method exists and access to it is not restricted, Sequel will call the setter method with the hash value. By default, there are two types of setter methods that are restricted.

The first is methods like typecast_on_assignment= and ==, which don't affect columns. These methods cannot be enabled for mass assignment. The second is primary key setters. To enable use of primary key setters, you need to call unrestrict_primary_key for that model:


Since mass assignment by default allows modification of all column values except for primary key columns, it can be a security risk in some cases. Sequel has multiple ways of securing mass assignment. The first way is using set_allowed_columns:

Post.set_allowed_columns :title, :body, :category

This explicitly sets which methods are allowed (title=, body=, and category=), all other methods will not be allowed. This method is useful in simple applications where the same columns are allowed in all cases, but not appropriate when different columns are allowed in different scenarios (e.g. admin access vs. user access). To handle cases where different columns are allowed in different cases, you can use set_only or update_only:

# user case
post.set_only(params[:post], :title, :body)
# admin case
post.set_only(params[:post], :title, :body, :deleted)

In this case, only the title= and body= methods will be allowed in the mass assignment in the user case, and only title=, body=, and deleted= will be allowed for mass assignment in the admin case.

By default, if an invalid setter method call is attempted, Sequel raises a Sequel::Error exception. You can have Sequel silently ignore invalid calls by doing:

# Global default
Sequel::Model.strict_param_setting = false
# Class level
Post.strict_param_setting = false
# Instance level
post.strict_param_setting = false

In addition to set_only and update_only, Sequel also has set_fields and update_fields methods, and these may be a better mass assignment choice for most users. These methods take two arguments, the attributes hash as the first argument, and a single array of valid field names as the second argument:

post.set_fields(params[:post], [:title, :body])

set_fields and update_fields differ in implementation from set_only and update_only. With set_only and update_only, the hash is iterated over and it checks each method call attempt to see if it is valid. With set_fields and update_fields, the array is iterated over, and it just looks up the value in the hash and calls the appropriate setter method.

set_fields and update_fields are designed for the case where you are expecting specific fields in the input, and want to ignore the other fields. They work great for things like HTML forms where the form fields are static. set_only and update_only are designed for cases where you are not sure what fields are going to be present in the input, but still want to make sure only certain setter methods can be called. They work great for flexible APIs.

set_fields and update_fields take an optional argument hash, and currently handles the :missing option. With :missing=>:skip, set_fields and update_fields will just skip missing entries in the hash, allowing them to be used in flexible APIs. With :missing=>:raise, set_fields and update_fields will raise an error if one of the entries in the hash is missing, instead of just assigning the value to nil or whatever the hash's default value is. That allows stricter checks, similar to the :strict_param_checking setting for the default mass assignment methods. You can use the Model.default_set_fields_options= method to set the default options to use for set_fields and update_fields on a global or per-model basis.

In all of the mass assignment cases, methods starting with set will set the attributes without saving the object, while methods starting with update will set the attributes and then save the changes to the object.