2013-10-14 02:36:58 +00:00
|
|
|
|
---
|
2017-09-02 18:57:25 +00:00
|
|
|
|
title: Rails models
|
2015-11-24 05:02:17 +00:00
|
|
|
|
category: Rails
|
2013-10-14 02:36:58 +00:00
|
|
|
|
---
|
2012-03-16 06:14:31 +00:00
|
|
|
|
|
2017-09-02 18:57:25 +00:00
|
|
|
|
Generating
|
|
|
|
|
----------
|
|
|
|
|
|
|
|
|
|
### Generating
|
|
|
|
|
|
|
|
|
|
$ rails g model User
|
|
|
|
|
|
|
|
|
|
Using models
|
|
|
|
|
------------
|
2015-05-22 01:16:46 +00:00
|
|
|
|
|
2017-09-02 18:57:25 +00:00
|
|
|
|
### Query methods
|
|
|
|
|
|
|
|
|
|
```ruby
|
2015-05-22 01:16:46 +00:00
|
|
|
|
items = Model
|
2015-11-13 00:58:37 +00:00
|
|
|
|
.where(first_name: 'Harvey')
|
|
|
|
|
.where('id = 3')
|
|
|
|
|
.where('id = ?', 3)
|
2017-09-02 18:57:25 +00:00
|
|
|
|
```
|
2015-05-22 01:16:46 +00:00
|
|
|
|
|
2017-09-02 18:57:25 +00:00
|
|
|
|
```ruby
|
2015-05-22 01:16:46 +00:00
|
|
|
|
.order(:title)
|
|
|
|
|
.order(title: :desc)
|
|
|
|
|
.order("title DESC")
|
2017-09-02 18:57:25 +00:00
|
|
|
|
```
|
2015-05-22 01:16:46 +00:00
|
|
|
|
|
2017-09-02 18:57:25 +00:00
|
|
|
|
```ruby
|
2015-11-13 00:58:37 +00:00
|
|
|
|
.reorder(:title) # discards other .order's
|
|
|
|
|
.rewhere(...) # discards other .where's
|
2017-09-02 18:57:25 +00:00
|
|
|
|
```
|
2015-05-22 01:16:46 +00:00
|
|
|
|
|
2017-09-02 18:57:25 +00:00
|
|
|
|
```ruby
|
2015-05-22 01:16:46 +00:00
|
|
|
|
.limit(2)
|
|
|
|
|
.offset(1)
|
|
|
|
|
.uniq
|
|
|
|
|
```
|
|
|
|
|
|
2017-09-02 18:57:25 +00:00
|
|
|
|
See: [QueryMethods](http://devdocs.io/rails/activerecord/querymethods)
|
|
|
|
|
|
|
|
|
|
### Advanced query methods
|
2015-11-13 00:58:37 +00:00
|
|
|
|
|
2017-09-02 18:57:25 +00:00
|
|
|
|
```ruby
|
|
|
|
|
items = Model
|
2015-11-13 00:58:37 +00:00
|
|
|
|
.select(:id)
|
|
|
|
|
.select([:id, :name])
|
2017-09-02 18:57:25 +00:00
|
|
|
|
```
|
2015-11-13 00:58:37 +00:00
|
|
|
|
|
2017-09-02 18:57:25 +00:00
|
|
|
|
```ruby
|
2015-11-13 00:58:37 +00:00
|
|
|
|
.group(:name) # GROUP BY name
|
|
|
|
|
.group('name AS grouped_name, age')
|
|
|
|
|
.having('SUM(price) > 30') # needs to be chained with .group
|
2017-09-02 18:57:25 +00:00
|
|
|
|
```
|
2015-11-13 00:58:37 +00:00
|
|
|
|
|
2017-09-02 18:57:25 +00:00
|
|
|
|
```ruby
|
2015-11-13 00:58:37 +00:00
|
|
|
|
.includes(:user)
|
|
|
|
|
.includes(user: [:articles])
|
2017-09-02 18:57:25 +00:00
|
|
|
|
```
|
2015-11-13 00:58:37 +00:00
|
|
|
|
|
2017-09-02 18:57:25 +00:00
|
|
|
|
```ruby
|
2015-11-13 00:58:37 +00:00
|
|
|
|
.references(:posts)
|
2017-09-02 18:57:25 +00:00
|
|
|
|
# aka: .where("posts.name = 'foo'").references(:posts)
|
2015-11-13 00:58:37 +00:00
|
|
|
|
```
|
|
|
|
|
|
2017-09-02 18:57:25 +00:00
|
|
|
|
### Finder methods
|
2015-05-22 01:16:46 +00:00
|
|
|
|
|
2017-09-02 18:57:25 +00:00
|
|
|
|
```ruby
|
2015-05-22 01:16:46 +00:00
|
|
|
|
item = Model.find(id)
|
|
|
|
|
item = Model.find_by_email(email)
|
|
|
|
|
item = Model.where(email: email).first
|
2017-09-02 18:57:25 +00:00
|
|
|
|
```
|
2015-05-22 01:16:46 +00:00
|
|
|
|
|
2017-09-02 18:57:25 +00:00
|
|
|
|
```ruby
|
2015-05-22 01:16:46 +00:00
|
|
|
|
Model
|
|
|
|
|
.exists?(5)
|
|
|
|
|
.exists?(name: "David")
|
2017-09-02 18:57:25 +00:00
|
|
|
|
```
|
2015-05-22 01:16:46 +00:00
|
|
|
|
|
2017-09-02 18:57:25 +00:00
|
|
|
|
```ruby
|
2015-05-22 01:16:46 +00:00
|
|
|
|
.first
|
|
|
|
|
.last
|
|
|
|
|
.find_nth(4, [offset])
|
|
|
|
|
```
|
|
|
|
|
|
2017-09-02 18:57:25 +00:00
|
|
|
|
See: [FinderMethods](http://devdocs.io/rails/activerecord/findermethods)
|
2015-05-22 01:16:46 +00:00
|
|
|
|
|
2017-09-02 18:57:25 +00:00
|
|
|
|
### Persistence
|
|
|
|
|
|
|
|
|
|
```ruby
|
2015-05-22 01:16:46 +00:00
|
|
|
|
item.new_record?
|
|
|
|
|
item.persisted?
|
|
|
|
|
item.destroyed?
|
|
|
|
|
|
|
|
|
|
item.serialize_hash
|
2017-09-02 18:57:25 +00:00
|
|
|
|
```
|
2015-05-22 01:16:46 +00:00
|
|
|
|
|
2017-09-02 18:57:25 +00:00
|
|
|
|
```ruby
|
2015-05-22 01:16:46 +00:00
|
|
|
|
item.save
|
|
|
|
|
item.save! # Same as above, but raises an Exception
|
2017-09-02 18:57:25 +00:00
|
|
|
|
```
|
2015-05-22 01:16:46 +00:00
|
|
|
|
|
2017-09-02 18:57:25 +00:00
|
|
|
|
```ruby
|
2015-11-24 08:18:12 +00:00
|
|
|
|
item.update name: 'John' # Saves immediately
|
|
|
|
|
item.update! name: 'John'
|
2017-09-02 18:57:25 +00:00
|
|
|
|
```
|
2015-05-22 01:16:46 +00:00
|
|
|
|
|
2017-09-02 18:57:25 +00:00
|
|
|
|
```ruby
|
2015-11-24 08:18:12 +00:00
|
|
|
|
item.update_column :name, 'John' # skips validations and callbacks
|
|
|
|
|
item.update_columns name: 'John'
|
|
|
|
|
item.update_columns! name: 'John'
|
2017-09-02 18:57:25 +00:00
|
|
|
|
```
|
2015-11-24 08:18:12 +00:00
|
|
|
|
|
2017-09-02 18:57:25 +00:00
|
|
|
|
```ruby
|
2015-11-24 08:18:12 +00:00
|
|
|
|
item.touch # updates :updated_at
|
2015-05-22 01:16:46 +00:00
|
|
|
|
item.touch :published_at
|
2017-09-02 18:57:25 +00:00
|
|
|
|
```
|
2015-05-22 01:16:46 +00:00
|
|
|
|
|
2017-09-02 18:57:25 +00:00
|
|
|
|
```ruby
|
2015-05-22 01:16:46 +00:00
|
|
|
|
item.destroy
|
|
|
|
|
item.delete # skips callbacks
|
|
|
|
|
```
|
|
|
|
|
|
2017-09-02 18:57:25 +00:00
|
|
|
|
```ruby
|
2015-05-22 01:16:46 +00:00
|
|
|
|
Model.create # Same an #new then #save
|
|
|
|
|
Model.create! # Same as above, but raises an Exception
|
|
|
|
|
```
|
|
|
|
|
|
2017-09-02 18:57:25 +00:00
|
|
|
|
See: [Persistence](http://devdocs.io/rails/activerecord/persistence)
|
|
|
|
|
|
|
|
|
|
### Attribute Assignment
|
2015-11-24 08:18:12 +00:00
|
|
|
|
|
2017-09-02 18:57:25 +00:00
|
|
|
|
```ruby
|
2015-11-24 08:18:12 +00:00
|
|
|
|
item.attributes # #<Hash>
|
2017-09-02 18:57:25 +00:00
|
|
|
|
```
|
2015-11-24 08:18:12 +00:00
|
|
|
|
|
2017-09-02 18:57:25 +00:00
|
|
|
|
```ruby
|
2015-11-24 08:18:12 +00:00
|
|
|
|
item.attributes = { name: 'John' } # Merges attributes in. Doesn't save.
|
|
|
|
|
item.assign_attributes name: 'John' # Same as above
|
|
|
|
|
```
|
|
|
|
|
|
2017-09-02 18:57:25 +00:00
|
|
|
|
See: [AttributeAssignment](http://devdocs.io/rails/activerecord/attributeassignment)
|
|
|
|
|
|
|
|
|
|
### Dirty
|
2015-11-24 07:33:12 +00:00
|
|
|
|
|
2017-09-02 18:57:25 +00:00
|
|
|
|
```ruby
|
2015-11-24 07:33:12 +00:00
|
|
|
|
item.changed?
|
|
|
|
|
item.changed # ['name']
|
|
|
|
|
item.changed_attributes # { 'name' => 'Bob' } - original values
|
|
|
|
|
item.changes # { 'name' => ['Bob', 'Robert'] }
|
|
|
|
|
item.previous_changes # available after #save
|
|
|
|
|
item.restore_attributes
|
2017-09-02 18:57:25 +00:00
|
|
|
|
```
|
2015-11-24 07:33:12 +00:00
|
|
|
|
|
2017-09-02 18:57:25 +00:00
|
|
|
|
```ruby
|
2015-11-24 07:33:12 +00:00
|
|
|
|
item.name = 'Robert'
|
|
|
|
|
item.name_was # 'Bob'
|
|
|
|
|
item.name_change # [ 'Bob', 'Robert' ]
|
|
|
|
|
item.name_changed? # true
|
|
|
|
|
item.name_changed?(from: 'Bob', to: 'Robert')
|
|
|
|
|
```
|
|
|
|
|
|
2017-09-02 18:57:25 +00:00
|
|
|
|
See: [Dirty](http://devdocs.io/rails/activemodel/dirty)
|
|
|
|
|
|
|
|
|
|
### Validations
|
2015-11-24 07:33:12 +00:00
|
|
|
|
|
2017-09-02 18:57:25 +00:00
|
|
|
|
```ruby
|
2015-11-24 07:33:12 +00:00
|
|
|
|
item.valid?
|
|
|
|
|
item.invalid?
|
|
|
|
|
```
|
|
|
|
|
|
2017-09-02 18:57:25 +00:00
|
|
|
|
See: [Validations](http://devdocs.io/rails/activerecord/validations)
|
|
|
|
|
|
|
|
|
|
### Calculations
|
2015-11-24 07:33:12 +00:00
|
|
|
|
|
2017-09-02 18:57:25 +00:00
|
|
|
|
```ruby
|
2015-11-24 07:33:12 +00:00
|
|
|
|
Person.count
|
|
|
|
|
Person.count(:age) # counts non-nil's
|
2017-09-02 18:57:25 +00:00
|
|
|
|
```
|
2015-11-24 07:33:12 +00:00
|
|
|
|
|
2017-09-02 18:57:25 +00:00
|
|
|
|
```ruby
|
2015-11-24 07:33:12 +00:00
|
|
|
|
Person.average(:age)
|
|
|
|
|
Person.maximum(:age)
|
|
|
|
|
Person.minimum(:age)
|
|
|
|
|
Person.sum('2 * age')
|
2017-09-02 18:57:25 +00:00
|
|
|
|
```
|
2015-05-22 01:16:46 +00:00
|
|
|
|
|
2017-09-02 18:57:25 +00:00
|
|
|
|
```ruby
|
2015-11-24 07:33:12 +00:00
|
|
|
|
Person.calculate(:count, :all)
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
Advanced:
|
|
|
|
|
|
2017-09-02 18:57:25 +00:00
|
|
|
|
```ruby
|
2015-11-24 07:33:12 +00:00
|
|
|
|
Person.distinct.count
|
|
|
|
|
Person.group(:city).count
|
|
|
|
|
```
|
2015-05-22 01:16:46 +00:00
|
|
|
|
|
2017-09-02 18:57:25 +00:00
|
|
|
|
See: [Calculations](http://devdocs.io/rails/activerecord/calculations)
|
2012-03-16 06:14:31 +00:00
|
|
|
|
|
2017-09-02 18:57:25 +00:00
|
|
|
|
### Dynamic attribute-based finders
|
|
|
|
|
|
|
|
|
|
Given a field called `name`:
|
|
|
|
|
{: .-setup}
|
|
|
|
|
|
|
|
|
|
```ruby
|
|
|
|
|
# Returns one record
|
|
|
|
|
Person.find_by_name(name)
|
|
|
|
|
Person.find_last_by_name(name)
|
|
|
|
|
Person.find_or_create_by_name(name)
|
|
|
|
|
Person.find_or_initialize_by_name(name)
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
```ruby
|
|
|
|
|
# Returns a list of records
|
|
|
|
|
Person.find_all_by_name(name)
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
```ruby
|
|
|
|
|
# Add a bang to make it raise an exception
|
|
|
|
|
Person.find_by_name!(name)
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
```ruby
|
|
|
|
|
# You may use `scoped` instead of `find`
|
|
|
|
|
Person.scoped_by_user_name
|
|
|
|
|
```
|
2012-03-16 06:14:31 +00:00
|
|
|
|
|
2015-05-22 01:16:46 +00:00
|
|
|
|
Associations
|
|
|
|
|
------------
|
2012-03-16 06:14:31 +00:00
|
|
|
|
|
2017-09-02 18:57:25 +00:00
|
|
|
|
### Associations
|
|
|
|
|
|
|
|
|
|
- `belongs_to`
|
|
|
|
|
- `has_one`
|
|
|
|
|
- `has_many`
|
|
|
|
|
- `has_many :through`
|
|
|
|
|
- `has_one :through`
|
|
|
|
|
- `has_and_belongs_to_many`
|
2012-03-16 06:14:31 +00:00
|
|
|
|
|
|
|
|
|
### Has many
|
|
|
|
|
|
2017-09-02 18:57:25 +00:00
|
|
|
|
```ruby
|
|
|
|
|
belongs_to :parent, :foreign_key => 'parent_id' class_name: 'Folder'
|
|
|
|
|
has_many :folders, :foreign_key => 'parent_id', class_name: 'Folder'
|
|
|
|
|
|
2019-05-17 15:21:58 +00:00
|
|
|
|
has_many :comments, -> { order('posted_on DESC') }
|
2017-09-02 18:57:25 +00:00
|
|
|
|
has_many :comments, :include => :author
|
|
|
|
|
has_many :people, :class_name => "Person"
|
|
|
|
|
has_many :people, :conditions => "deleted = 0"
|
2019-05-17 15:21:58 +00:00
|
|
|
|
has_many :tracks, -> { order(:position) }
|
2017-09-02 18:57:25 +00:00
|
|
|
|
has_many :comments, :dependent => :nullify
|
|
|
|
|
has_many :comments, :dependent => :destroy
|
|
|
|
|
has_many :tags, :as => :taggable
|
|
|
|
|
has_many :reports, :readonly => true
|
|
|
|
|
has_many :subscribers, :through => :subscriptions, class_name: "User", :source => :user
|
|
|
|
|
has_many :subscribers, :finder_sql =>
|
|
|
|
|
'SELECT DISTINCT people.* ' +
|
|
|
|
|
'FROM people p, post_subscriptions ps ' +
|
|
|
|
|
'WHERE ps.post_id = #{id} AND ps.person_id = p.id ' +
|
|
|
|
|
'ORDER BY p.first_name'
|
|
|
|
|
```
|
2012-03-16 06:14:31 +00:00
|
|
|
|
|
2012-12-15 12:56:59 +00:00
|
|
|
|
### belongs to
|
|
|
|
|
|
2017-09-02 18:57:25 +00:00
|
|
|
|
```ruby
|
|
|
|
|
belongs_to :author,
|
|
|
|
|
:dependent => :destroy # or :delete
|
2012-12-15 12:56:59 +00:00
|
|
|
|
|
2017-09-02 18:57:25 +00:00
|
|
|
|
:class_name => "Person"
|
|
|
|
|
:select => "*"
|
|
|
|
|
:counter_cache => true
|
|
|
|
|
:counter_cache => :custom_counter
|
|
|
|
|
:include => "Book"
|
|
|
|
|
:readonly => true
|
2012-12-15 12:56:59 +00:00
|
|
|
|
|
2017-09-02 18:57:25 +00:00
|
|
|
|
:conditions => 'published = true'
|
2012-12-15 12:56:59 +00:00
|
|
|
|
|
2017-09-02 18:57:25 +00:00
|
|
|
|
:touch => true
|
|
|
|
|
:touch => :authors_last_updated_at
|
2012-12-15 12:56:59 +00:00
|
|
|
|
|
2017-09-02 18:57:25 +00:00
|
|
|
|
:primary_key => "name"
|
|
|
|
|
:foreign_key => "author_name"
|
|
|
|
|
```
|
2012-12-15 12:56:59 +00:00
|
|
|
|
|
2012-03-16 06:14:31 +00:00
|
|
|
|
### Many-to-many
|
|
|
|
|
|
|
|
|
|
If you have a join model:
|
2017-09-02 18:57:25 +00:00
|
|
|
|
{: .-setup}
|
2012-03-16 06:14:31 +00:00
|
|
|
|
|
2017-09-02 18:57:25 +00:00
|
|
|
|
```ruby
|
|
|
|
|
class Programmer < ActiveRecord::Base
|
|
|
|
|
has_many :assignments
|
|
|
|
|
has_many :projects, :through => :assignments
|
|
|
|
|
end
|
|
|
|
|
```
|
|
|
|
|
{: data-line="2,3"}
|
2012-03-16 06:14:31 +00:00
|
|
|
|
|
2017-09-02 18:57:25 +00:00
|
|
|
|
```ruby
|
|
|
|
|
class Project < ActiveRecord::Base
|
|
|
|
|
has_many :assignments
|
|
|
|
|
has_many :programmers, :through => :assignments
|
|
|
|
|
end
|
|
|
|
|
```
|
|
|
|
|
{: data-line="2,3"}
|
2012-03-16 06:14:31 +00:00
|
|
|
|
|
2017-09-02 18:57:25 +00:00
|
|
|
|
```ruby
|
|
|
|
|
class Assignment
|
|
|
|
|
belongs_to :project
|
|
|
|
|
belongs_to :programmer
|
|
|
|
|
end
|
|
|
|
|
```
|
|
|
|
|
{: data-line="2,3"}
|
|
|
|
|
|
|
|
|
|
### Many-to-many (HABTM)
|
|
|
|
|
|
|
|
|
|
```ruby
|
|
|
|
|
has_and_belongs_to_many :projects
|
|
|
|
|
has_and_belongs_to_many :projects, :include => [ :milestones, :manager ]
|
|
|
|
|
has_and_belongs_to_many :nations, :class_name => "Country"
|
|
|
|
|
has_and_belongs_to_many :categories, :join_table => "prods_cats"
|
|
|
|
|
has_and_belongs_to_many :categories, :readonly => true
|
|
|
|
|
has_and_belongs_to_many :active_projects, :join_table => 'developers_projects', :delete_sql =>
|
|
|
|
|
"DELETE FROM developers_projects WHERE active=1 AND developer_id = #{id} AND project_id = #{record.id}"
|
|
|
|
|
```
|
2012-03-16 06:14:31 +00:00
|
|
|
|
|
|
|
|
|
### Polymorphic associations
|
|
|
|
|
|
2017-09-02 18:57:25 +00:00
|
|
|
|
```ruby
|
|
|
|
|
class Post
|
|
|
|
|
has_many :attachments, as: :parent
|
|
|
|
|
end
|
|
|
|
|
```
|
|
|
|
|
{: data-line="2"}
|
2012-03-16 06:14:31 +00:00
|
|
|
|
|
2017-09-02 18:57:25 +00:00
|
|
|
|
```ruby
|
|
|
|
|
class Image
|
|
|
|
|
belongs_to :parent, polymorphic: true
|
|
|
|
|
end
|
|
|
|
|
```
|
|
|
|
|
{: data-line="2"}
|
2012-03-16 06:14:31 +00:00
|
|
|
|
|
|
|
|
|
And in migrations:
|
|
|
|
|
|
2017-09-02 18:57:25 +00:00
|
|
|
|
```ruby
|
|
|
|
|
create_table :images do |t|
|
|
|
|
|
t.references :post, polymorphic: true
|
|
|
|
|
end
|
|
|
|
|
```
|
|
|
|
|
{: data-line="2"}
|
2012-03-21 06:15:34 +00:00
|
|
|
|
|
2012-03-16 06:14:31 +00:00
|
|
|
|
Validation
|
|
|
|
|
----------
|
|
|
|
|
|
2017-09-02 18:57:25 +00:00
|
|
|
|
### Validation
|
|
|
|
|
|
|
|
|
|
```ruby
|
|
|
|
|
class Person < ActiveRecord::Base
|
|
|
|
|
```
|
|
|
|
|
{:.-setup}
|
|
|
|
|
|
|
|
|
|
```ruby
|
|
|
|
|
# Presence
|
|
|
|
|
validates :name, presence: true
|
|
|
|
|
```
|
|
|
|
|
{: data-line="2"}
|
2012-03-16 06:14:31 +00:00
|
|
|
|
|
2017-09-02 18:57:25 +00:00
|
|
|
|
```ruby
|
|
|
|
|
# Acceptance
|
|
|
|
|
validates :terms, acceptance: true
|
|
|
|
|
```
|
2012-10-11 08:13:19 +00:00
|
|
|
|
|
2017-09-02 18:57:25 +00:00
|
|
|
|
```ruby
|
|
|
|
|
# Confirm
|
|
|
|
|
validates :email, confirmation: true
|
|
|
|
|
```
|
2012-03-16 06:14:31 +00:00
|
|
|
|
|
2017-09-02 18:57:25 +00:00
|
|
|
|
```ruby
|
|
|
|
|
# Unique
|
|
|
|
|
validates :slug, uniqueness: true
|
|
|
|
|
validates :slug, uniqueness: { case_sensitive: false }
|
|
|
|
|
validates :holiday, uniqueness: { scope: :year, message: 'yearly only' }
|
|
|
|
|
```
|
2012-03-16 06:14:31 +00:00
|
|
|
|
|
2017-09-02 18:57:25 +00:00
|
|
|
|
```ruby
|
|
|
|
|
# Format
|
|
|
|
|
validates :code, format: /regex/
|
|
|
|
|
validates :code, format: { with: /regex/ }
|
|
|
|
|
```
|
2012-03-16 06:14:31 +00:00
|
|
|
|
|
2017-09-02 18:57:25 +00:00
|
|
|
|
```ruby
|
|
|
|
|
# Length
|
|
|
|
|
validates :name, length: { minimum: 2 }
|
|
|
|
|
validates :bio, length: { maximum: 500 }
|
|
|
|
|
validates :password, length: { in: => 6..20 }
|
|
|
|
|
validates :number, length: { is: => 6 }
|
|
|
|
|
```
|
2012-10-11 08:13:19 +00:00
|
|
|
|
|
2017-09-02 18:57:25 +00:00
|
|
|
|
```ruby
|
|
|
|
|
# Include/exclude
|
|
|
|
|
validates :gender, inclusion: %w(male female)
|
|
|
|
|
validates :gender, inclusion: { in: %w(male female) }
|
|
|
|
|
validates :lol, exclusion: %w(xyz)
|
|
|
|
|
```
|
2012-03-16 06:14:31 +00:00
|
|
|
|
|
2017-09-02 18:57:25 +00:00
|
|
|
|
```ruby
|
|
|
|
|
# Numeric
|
|
|
|
|
validates :points, numericality: true
|
|
|
|
|
validates :played, numericality: { only_integer: true }
|
|
|
|
|
# ... greater_than, greater_than_or_equal_to,
|
|
|
|
|
# ... less_than, less_than_or_equal_to
|
|
|
|
|
# ... odd, even, equal_to
|
|
|
|
|
```
|
2012-03-16 06:14:31 +00:00
|
|
|
|
|
2017-09-02 18:57:25 +00:00
|
|
|
|
```ruby
|
|
|
|
|
# Validate the associated records to ensure they're valid as well
|
|
|
|
|
has_many :books
|
|
|
|
|
validates_associated :books
|
|
|
|
|
```
|
2015-01-16 04:02:16 +00:00
|
|
|
|
|
2017-09-02 18:57:25 +00:00
|
|
|
|
```ruby
|
|
|
|
|
# Length (full options)
|
|
|
|
|
validates :content, length: {
|
|
|
|
|
minimum: 300,
|
|
|
|
|
maximum: 400,
|
|
|
|
|
tokenizer: lambda { |str| str.scan(/\w+/) },
|
|
|
|
|
too_short: "must have at least %{count} words",
|
|
|
|
|
too_long: "must have at most %{count} words" }
|
|
|
|
|
```
|
2012-03-16 06:14:31 +00:00
|
|
|
|
|
2017-09-02 18:57:25 +00:00
|
|
|
|
```ruby
|
|
|
|
|
# Multiple
|
|
|
|
|
validates :login, :email, presence: true
|
|
|
|
|
```
|
2012-03-16 06:14:31 +00:00
|
|
|
|
|
2017-09-02 18:57:25 +00:00
|
|
|
|
```ruby
|
|
|
|
|
# Conditional
|
|
|
|
|
validates :description, presence: true, if: :published?
|
|
|
|
|
validates :description, presence: true, if: lambda { |obj| .. }
|
|
|
|
|
```
|
2012-10-11 08:13:19 +00:00
|
|
|
|
|
2017-09-02 18:57:25 +00:00
|
|
|
|
```ruby
|
|
|
|
|
validates :title, presence: true, on: :save # :save | :create | :update
|
|
|
|
|
```
|
2012-10-11 08:13:19 +00:00
|
|
|
|
|
2017-09-02 18:57:25 +00:00
|
|
|
|
```ruby
|
|
|
|
|
end
|
|
|
|
|
```
|
|
|
|
|
{: .-setup}
|
2012-03-16 06:14:31 +00:00
|
|
|
|
|
|
|
|
|
### Custom validations
|
|
|
|
|
|
2017-09-02 18:57:25 +00:00
|
|
|
|
```ruby
|
|
|
|
|
class Person < ActiveRecord::Base
|
|
|
|
|
validate :foo_cant_be_nil
|
2012-03-16 06:14:31 +00:00
|
|
|
|
|
2017-09-02 18:57:25 +00:00
|
|
|
|
def foo_cant_be_nil
|
|
|
|
|
errors.add(:foo, 'cant be nil') if foo.nil?
|
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
```
|
|
|
|
|
{: data-line="2"}
|
2012-10-11 08:13:19 +00:00
|
|
|
|
|
2012-10-11 09:05:38 +00:00
|
|
|
|
### Errors
|
|
|
|
|
|
2017-09-02 18:57:25 +00:00
|
|
|
|
```ruby
|
|
|
|
|
record.errors.valid? # → false
|
|
|
|
|
record.errors # → { :name => ["can't be blank"] }
|
|
|
|
|
record.errors.messages # → { :name => ["can't be blank"] }
|
|
|
|
|
```
|
2012-10-11 09:05:38 +00:00
|
|
|
|
|
2017-09-02 18:57:25 +00:00
|
|
|
|
```ruby
|
|
|
|
|
record.errors[:name].any?
|
|
|
|
|
```
|
2012-10-11 09:05:38 +00:00
|
|
|
|
|
2015-05-22 01:16:46 +00:00
|
|
|
|
Other API
|
|
|
|
|
---------
|
2012-03-16 06:14:31 +00:00
|
|
|
|
|
2015-05-22 01:16:46 +00:00
|
|
|
|
### Callbacks
|
2012-03-16 06:14:31 +00:00
|
|
|
|
|
2012-11-25 04:13:51 +00:00
|
|
|
|
* [Guides: callbacks](http://guides.rubyonrails.org/active_record_validations_callbacks.html)
|
2012-03-16 06:14:31 +00:00
|
|
|
|
|
|
|
|
|
### Mass updates
|
|
|
|
|
|
2017-09-02 18:57:25 +00:00
|
|
|
|
```ruby
|
|
|
|
|
# Updates person id 15
|
|
|
|
|
Person.update 15, name: "John", age: 24
|
|
|
|
|
Person.update [1,2], [{name: "John"}, {name: "foo"}]
|
|
|
|
|
```
|
2012-03-16 06:14:31 +00:00
|
|
|
|
|
|
|
|
|
### Joining
|
|
|
|
|
|
2017-09-02 18:57:25 +00:00
|
|
|
|
```ruby
|
|
|
|
|
# Basic joins
|
|
|
|
|
Student.joins(:schools).where(schools: { type: 'public' })
|
|
|
|
|
Student.joins(:schools).where('schools.type' => 'public' )
|
|
|
|
|
```
|
2012-03-16 06:14:31 +00:00
|
|
|
|
|
2017-09-02 18:57:25 +00:00
|
|
|
|
```ruby
|
|
|
|
|
# Multiple associations
|
|
|
|
|
Article.joins(:category, :comments)
|
|
|
|
|
```
|
2017-07-30 09:59:47 +00:00
|
|
|
|
|
2017-09-02 18:57:25 +00:00
|
|
|
|
```ruby
|
2018-06-14 15:48:42 +00:00
|
|
|
|
# Nested associations
|
2017-09-02 18:57:25 +00:00
|
|
|
|
Article.joins(comments: :guest)
|
|
|
|
|
```
|
2017-07-30 09:59:47 +00:00
|
|
|
|
|
2017-09-02 18:57:25 +00:00
|
|
|
|
```ruby
|
|
|
|
|
# SQL
|
|
|
|
|
Author.joins(
|
|
|
|
|
'INNER JOIN posts ' +
|
|
|
|
|
'ON posts.author_id = authors.id ' +
|
|
|
|
|
'AND posts.published = "t"'
|
|
|
|
|
)
|
|
|
|
|
```
|
2017-07-30 09:59:47 +00:00
|
|
|
|
|
2015-01-16 04:02:16 +00:00
|
|
|
|
### Where interpolation
|
|
|
|
|
|
2017-09-02 18:57:25 +00:00
|
|
|
|
```ruby
|
|
|
|
|
where('name = ?', 'John')
|
|
|
|
|
where(['name = :name', { name: 'John' }])
|
|
|
|
|
```
|
2015-01-16 04:02:16 +00:00
|
|
|
|
|
2012-03-16 06:14:31 +00:00
|
|
|
|
### Serialize
|
|
|
|
|
|
2017-09-02 18:57:25 +00:00
|
|
|
|
```ruby
|
|
|
|
|
class User < ActiveRecord::Base
|
|
|
|
|
serialize :preferences
|
|
|
|
|
end
|
|
|
|
|
```
|
|
|
|
|
{: data-line="2"}
|
|
|
|
|
|
|
|
|
|
```ruby
|
|
|
|
|
user = User.create(
|
|
|
|
|
preferences: {
|
|
|
|
|
'background' => 'black',
|
|
|
|
|
'display' => 'large'
|
|
|
|
|
}
|
|
|
|
|
)
|
|
|
|
|
```
|
2012-03-16 06:14:31 +00:00
|
|
|
|
|
|
|
|
|
You can also specify a class option as the second parameter that’ll raise an
|
|
|
|
|
exception if a serialized object is retrieved as a descendant of a class not in
|
|
|
|
|
the hierarchy.
|
|
|
|
|
|
2017-09-02 18:57:25 +00:00
|
|
|
|
```ruby
|
|
|
|
|
# Only Hash allowed!
|
|
|
|
|
class User < ActiveRecord::Base
|
|
|
|
|
serialize :preferences, Hash
|
|
|
|
|
end
|
|
|
|
|
```
|
|
|
|
|
{: data-line="3"}
|
|
|
|
|
|
|
|
|
|
```ruby
|
|
|
|
|
# Reading it raises SerializationTypeMismatch
|
|
|
|
|
user = User.create(preferences: %w(one two three))
|
|
|
|
|
User.find(user.id).preferences
|
|
|
|
|
```
|
2012-03-16 06:14:31 +00:00
|
|
|
|
|
2017-09-02 18:57:25 +00:00
|
|
|
|
Other tricks
|
|
|
|
|
------------
|
2012-03-16 06:14:31 +00:00
|
|
|
|
|
2017-09-02 18:57:25 +00:00
|
|
|
|
### Overriding accessors
|
2012-03-16 06:14:31 +00:00
|
|
|
|
|
2017-09-02 18:57:25 +00:00
|
|
|
|
```ruby
|
|
|
|
|
class Song < ActiveRecord::Base
|
|
|
|
|
# Uses an integer of seconds to hold the length of the song
|
2012-03-16 06:14:31 +00:00
|
|
|
|
|
2017-09-02 18:57:25 +00:00
|
|
|
|
def length=(minutes)
|
|
|
|
|
write_attribute(:length, minutes.to_i * 60)
|
|
|
|
|
end
|
2012-03-16 06:14:31 +00:00
|
|
|
|
|
2017-09-02 18:57:25 +00:00
|
|
|
|
def length
|
|
|
|
|
read_attribute(:length) / 60
|
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
```
|
|
|
|
|
{: data-line="4,8"}
|
2012-03-16 06:14:31 +00:00
|
|
|
|
|
2017-09-02 18:57:25 +00:00
|
|
|
|
See: <http://api.rubyonrails.org/classes/ActiveRecord/Base.html>
|
2012-03-16 06:14:31 +00:00
|
|
|
|
|
|
|
|
|
Callbacks
|
|
|
|
|
---------
|
|
|
|
|
|
2017-09-02 18:57:25 +00:00
|
|
|
|
- after_initialize
|
2022-02-20 23:37:42 +00:00
|
|
|
|
- before_validation / after_validation
|
|
|
|
|
- before_save / after_save / around_save
|
|
|
|
|
- before_create / after_create / around_create
|
|
|
|
|
- before_update / after_update / around_update
|
|
|
|
|
- before_destroy / after_destroy / around_destroy
|
2017-09-02 18:57:25 +00:00
|
|
|
|
- after_commit
|
2022-02-20 23:37:42 +00:00
|
|
|
|
- after_rollback
|
|
|
|
|
|
|
|
|
|
See: [ActiveRecord Callbacks](https://guides.rubyonrails.org/active_record_callbacks.html)
|