You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Afterwards you can use it (almost) like an `ActiveRecord::Relation`.
30
+
As an alternative, it's also possible to create a collection for a model without explicitly passing a collection.
31
+
In this case, the library will attempt to call `Project.records` to get the default collection. If the method doesn't exist or returns `nil`, the collection will default to an empty array.
32
+
33
+
```ruby
34
+
classProject
35
+
defself.records
36
+
[
37
+
Project.new(id:1, state:'draft', priority:1),
38
+
Project.new(id:2, state:'running', priority:2),
39
+
Project.new(id:3, state:'completed', priority:3),
40
+
Project.new(id:4, state:'completed', priority:1)
41
+
]
42
+
end
43
+
end
44
+
45
+
relation =ActiveModel::Relation.new(Project)
46
+
```
47
+
48
+
### Querying
49
+
50
+
An `ActiveModel::Relation` can be queried almost exactly like an `ActiveRecord::Relation`.
51
+
52
+
#### `#find`
53
+
54
+
You can look up a record by it's primary key, using the `find` method. If no record is found, it will raise a `ActiveModel::Relation::RecordNotFound` error.
55
+
56
+
```ruby
57
+
project = relation.find(1)
58
+
```
59
+
60
+
By default, `ActiveModel::Relation` will assume `:id` as the primary key. You can customize this behavior by setting a `primary_key` on the model class.
61
+
62
+
```ruby
63
+
classProject
64
+
defself.primary_key=:identifier
65
+
end
66
+
```
67
+
68
+
When passed a block, the `find` method will behave like `Enumerable#find`.
69
+
70
+
```ruby
71
+
project = relation.find { |p| p.id ==1 }
72
+
```
73
+
74
+
#### `#find_by`
75
+
76
+
To look up a record based on a set of arbitary attributes, you can use `find_by`. It accepts the same arguments as `#where` and will return the first matching record.
77
+
78
+
```ruby
79
+
project = relation.find_by(state:'draft')
80
+
```
81
+
82
+
#### `#where`
83
+
84
+
To filter a relation, you can use `where` and pass a set of attributes and the expected values. This method will return a new `ActiveModel::Relation` that only returns the matching records, so it's possible to chain multiple calls. The filtering will only happen when actually accessing records.
29
85
30
86
```ruby
31
-
relation.find(1)
32
-
relation.find_by(state:'draft')
33
87
relation.where(state:'completed')
88
+
```
89
+
90
+
The following two lines will return the same filtered results:
To allow for more advanced filtering, `#where` allows filtering using a block. This works similar to `Enumerable#select`, but will return a new `ActiveModel::Relation` instead of an already filtered array.
Similar to `#where`, the `#where.not` chain allows you to filter a relation. It will also return a new `ActiveModel::Relation` with that returns only the matching records.
106
+
107
+
```ruby
34
108
relation.where.not(state:'draft')
35
-
relation.offset(3)
36
-
relation.limit(2)
109
+
```
110
+
111
+
To allow for more advanced filtering, `#where.not` allows filtering using a block. This works similar to `Enumerable#reject`, but will return a new `ActiveModel::Relation` instead of an already filtered array.
It is possible to sort an `ActiveModel::Relation` by a given set of attribute names. Sorting will be applied after filtering, but before limits and offsets.
120
+
121
+
#### `#order`
122
+
123
+
To sort by a single attribute in ascending order, you can just pass the attribute name to the `order` method.
124
+
125
+
```ruby
37
126
relation.order(:priority)
38
-
relation.order(priority::asc, state::desc)
39
-
relation.extending(Pagination)
40
-
relation.only(:where)
41
-
relation.except(:limit, :offset)
42
127
```
43
128
44
-
It's also possible to use method calls for filtering, while still returning a `ActiveModel::Relation`.
129
+
To specify the sort direction, you can pass a hash with the attribute name as key and either `:asc`, or `:desc` as value.
45
130
46
131
```ruby
47
-
relation.where { |project| project.completed? }
48
-
relation.where.not { |project| project.draft? }
132
+
relation.order(priorty::desc)
49
133
```
50
134
51
-
After including `ActiveModel::Relation::Model`, the library also supports named scope methods on the model class.
135
+
To order by multiple attributes, you can pass them in the order of specificity you want.
136
+
137
+
```ruby
138
+
relation.order(:state, :priority)
139
+
```
140
+
141
+
For multiple attributes, it's also possible to specify the direction.
142
+
143
+
```ruby
144
+
relation.order(state::desc, priority::asc)
145
+
```
146
+
147
+
### Limiting and offsets
148
+
149
+
#### `#limit`
150
+
151
+
To limit the amount of records returned in the collection, you can call `limit` on the relation. It will return a new `ActiveModel::Relation` that only returns the given limit of records, allowing you to chain multiple other calls. The limit will only be applied when actually accessing the records later on.
152
+
153
+
```ruby
154
+
relation.limit(10)
155
+
```
156
+
157
+
#### `#offset`
158
+
159
+
To skip a certain number of records in the collection, you can use `offset` on the relation. It will return a new `ActiveModel::Relation` that skips the given number of records at the beginning. The offset will only be applied when actually accessing the records later on.
160
+
161
+
```ruby
162
+
relation.offset(20)
163
+
```
164
+
165
+
### Scopes
166
+
167
+
After including `ActiveModel::Relation::Model`, the library also supports calling class methods defined on the model class as part of the relation.
52
168
53
169
```ruby
54
170
classProject
@@ -64,8 +180,71 @@ class Project
64
180
where(state:'completed')
65
181
end
66
182
end
183
+
```
184
+
185
+
Given the example above, you can now create relations like you're used to from `ActiveRecord::Relation`.
It's possilbe to create new versions of a `ActiveModel::Relation` that only includes certain aspects of the `ActiveModel::Relation` it is based on. It's currently possible to customize the following aspects: `:where`, `:limit`, `:offset`.
196
+
197
+
#### `#except`
198
+
199
+
To create a new `ActiveModel::Relation` without certain aspects, you can use `except` and pass a list of aspects, you'd like to exclude from the newly created instance. The following example will create a new `ActiveModel::Relation` without any previously defined limit or offset.
200
+
201
+
```ruby
202
+
relation.except(:limit, :offset)
203
+
```
204
+
#### `#only`
205
+
206
+
Similar to `except`, the `only` method will return a new instance of the `ActiveModel::Relation` it is based on but with only the passed list of aspects applied to it.
207
+
208
+
```ruby
209
+
relation.only(:where)
210
+
```
211
+
212
+
### Extending relations
213
+
214
+
#### `#extending`
215
+
216
+
In order to add additional methods to a relation, you can use `extending`. You can either pass a list of modules that will be included in this particular instance, or a block defining additional methods.
217
+
218
+
```ruby
219
+
modulePagination
220
+
defpage_size=25
221
+
222
+
defpage(page)
223
+
limit(page_size).offset(page.to_i * page_size)
224
+
end
225
+
226
+
deftotal_count
227
+
except(:limit, :offset).count
228
+
end
229
+
end
230
+
231
+
relation.extending(Pagination)
232
+
```
67
233
68
-
relation.completed
234
+
The following example is equivalent to the example above:
0 commit comments