activerecord-hashlike_access 0.1.1 → 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/Gemfile.lock +2 -2
- data/README.md +9 -1
- data/docs/ActiveRecord/HashlikeAccess.html +810 -0
- data/docs/ActiveRecord.html +122 -0
- data/docs/_index.html +139 -0
- data/docs/class_list.html +54 -0
- data/docs/css/common.css +1 -0
- data/docs/css/full_list.css +206 -0
- data/docs/css/style.css +1089 -0
- data/docs/file.README.html +289 -0
- data/docs/file_list.html +59 -0
- data/docs/frames.html +22 -0
- data/docs/index.html +289 -0
- data/docs/js/app.js +801 -0
- data/docs/js/full_list.js +334 -0
- data/docs/js/jquery.js +4 -0
- data/docs/method_list.html +102 -0
- data/docs/top-level-namespace.html +112 -0
- data/lib/active_record/hashlike_access/auto_extend.rb +6 -0
- data/lib/active_record/hashlike_access/version.rb +1 -1
- metadata +18 -1
|
@@ -0,0 +1,289 @@
|
|
|
1
|
+
<!DOCTYPE html>
|
|
2
|
+
<html>
|
|
3
|
+
<head>
|
|
4
|
+
<meta charset="UTF-8">
|
|
5
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
6
|
+
<title>
|
|
7
|
+
File: README
|
|
8
|
+
|
|
9
|
+
— Documentation by YARD 0.9.45
|
|
10
|
+
|
|
11
|
+
</title>
|
|
12
|
+
|
|
13
|
+
<link rel="stylesheet" href="css/style.css" type="text/css">
|
|
14
|
+
|
|
15
|
+
<link rel="stylesheet" href="css/common.css" type="text/css">
|
|
16
|
+
|
|
17
|
+
<script type="text/javascript">
|
|
18
|
+
pathId = "README";
|
|
19
|
+
relpath = '';
|
|
20
|
+
</script>
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
<script type="text/javascript" charset="utf-8" src="js/jquery.js"></script>
|
|
24
|
+
|
|
25
|
+
<script type="text/javascript" charset="utf-8" src="js/app.js"></script>
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
</head>
|
|
29
|
+
<body>
|
|
30
|
+
<div id="main_progress" aria-hidden="true"></div>
|
|
31
|
+
|
|
32
|
+
<div class="nav_wrap">
|
|
33
|
+
<iframe id="nav" src="file_list.html?1"></iframe>
|
|
34
|
+
<div id="resizer"></div>
|
|
35
|
+
</div>
|
|
36
|
+
|
|
37
|
+
<div id="main" tabindex="-1">
|
|
38
|
+
<div id="header">
|
|
39
|
+
<div id="menu">
|
|
40
|
+
|
|
41
|
+
<a href="_index.html">Index</a> »
|
|
42
|
+
<span class="title">File: README</span>
|
|
43
|
+
|
|
44
|
+
</div>
|
|
45
|
+
|
|
46
|
+
<div id="search">
|
|
47
|
+
|
|
48
|
+
<a class="full_list_link" id="class_list_link"
|
|
49
|
+
href="class_list.html">
|
|
50
|
+
|
|
51
|
+
<svg width="24" height="24">
|
|
52
|
+
<rect x="0" y="4" width="24" height="4" rx="1" ry="1"></rect>
|
|
53
|
+
<rect x="0" y="12" width="24" height="4" rx="1" ry="1"></rect>
|
|
54
|
+
<rect x="0" y="20" width="24" height="4" rx="1" ry="1"></rect>
|
|
55
|
+
</svg>
|
|
56
|
+
</a>
|
|
57
|
+
|
|
58
|
+
</div>
|
|
59
|
+
<div class="clear"></div>
|
|
60
|
+
</div>
|
|
61
|
+
|
|
62
|
+
<div id="content"><div id='filecontents'><p><a href="https://tldrlegal.com/license/mit-license"><img src="https://img.shields.io/github/license/nestor-custodio/activerecord-hashlike_access" alt="MIT License" /></a></p>
|
|
63
|
+
<h1 id="ActiveRecord__HashlikeAccess">ActiveRecord::HashlikeAccess</h1>
|
|
64
|
+
<p>Pulling this module into your ActiveRecord models gives you Hash-like getters (<code>[]</code>) and setters (<code>[]=</code>) for <em>individual records/values</em>. This is not only slightly cleaner to read/write, but also encourages fetching items by either their <code>id</code> or a canonical "lookup field", minimizing the likelihood of pulling records by an unindexed field.</p>
|
|
65
|
+
<p>In simplest terms:</p>
|
|
66
|
+
<pre class="code ruby"><code class="ruby"><span class='comment'># Given a "roles" table with
|
|
67
|
+
</span><span class='comment'># `id`, `name`, and `display_text`...
|
|
68
|
+
</span>
|
|
69
|
+
|
|
70
|
+
<span class='comment'># Hash-Like Access to Records:
|
|
71
|
+
</span>
|
|
72
|
+
<span class='kw'>class</span> <span class='const'>Role</span> <span class='op'><</span> <span class='const'>ApplicationRecord</span>
|
|
73
|
+
<span class='id identifier rubyid_extend'>extend</span> <span class='const'><span class='object_link'><a href="ActiveRecord.html" title="ActiveRecord (module)">ActiveRecord</a></span></span><span class='op'>::</span><span class='const'><span class='object_link'><a href="ActiveRecord/HashlikeAccess.html" title="ActiveRecord::HashlikeAccess (module)">HashlikeAccess</a></span></span>
|
|
74
|
+
<span class='id identifier rubyid_hashlike_access'>hashlike_access</span> <span class='label'>by:</span> <span class='symbol'>:name</span>
|
|
75
|
+
<span class='kw'>end</span>
|
|
76
|
+
|
|
77
|
+
<span class='id identifier rubyid_role'>role</span> <span class='op'>=</span> <span class='const'>Role</span><span class='period'>.</span><span class='id identifier rubyid_find_by'>find_by</span> <span class='label'>name:</span> <span class='id identifier rubyid_name'>name</span>
|
|
78
|
+
<span class='comment'># ... becomes ...
|
|
79
|
+
</span><span class='id identifier rubyid_role'>role</span> <span class='op'>=</span> <span class='const'>Role</span><span class='lbracket'>[</span><span class='id identifier rubyid_name'>name</span><span class='rbracket'>]</span>
|
|
80
|
+
|
|
81
|
+
|
|
82
|
+
<span class='comment'># Hash-Like Access to Values:
|
|
83
|
+
</span>
|
|
84
|
+
<span class='kw'>class</span> <span class='const'>Role</span> <span class='op'><</span> <span class='const'>ApplicationRecord</span>
|
|
85
|
+
<span class='id identifier rubyid_extend'>extend</span> <span class='const'><span class='object_link'><a href="ActiveRecord.html" title="ActiveRecord (module)">ActiveRecord</a></span></span><span class='op'>::</span><span class='const'><span class='object_link'><a href="ActiveRecord/HashlikeAccess.html" title="ActiveRecord::HashlikeAccess (module)">HashlikeAccess</a></span></span>
|
|
86
|
+
<span class='id identifier rubyid_hashlike_access'>hashlike_access</span> <span class='label'>to:</span> <span class='symbol'>:display_text</span><span class='comma'>,</span> <span class='label'>by:</span> <span class='symbol'>:name</span>
|
|
87
|
+
<span class='kw'>end</span>
|
|
88
|
+
|
|
89
|
+
<span class='id identifier rubyid_role_display_text'>role_display_text</span> <span class='op'>=</span> <span class='const'>Role</span><span class='period'>.</span><span class='id identifier rubyid_find_by'>find_by</span><span class='lparen'>(</span><span class='label'>name:</span> <span class='id identifier rubyid_name'>name</span><span class='rparen'>)</span><span class='period'>.</span><span class='id identifier rubyid_display_text'>display_text</span>
|
|
90
|
+
<span class='comment'># ... becomes ...
|
|
91
|
+
</span><span class='id identifier rubyid_role_display_text'>role_display_text</span> <span class='op'>=</span> <span class='const'>Role</span><span class='lbracket'>[</span><span class='id identifier rubyid_name'>name</span><span class='rbracket'>]</span>
|
|
92
|
+
|
|
93
|
+
<span class='const'>Role</span><span class='period'>.</span><span class='id identifier rubyid_find_by'>find_by</span><span class='lparen'>(</span><span class='label'>name:</span> <span class='id identifier rubyid_name'>name</span><span class='rparen'>)</span><span class='period'>.</span><span class='id identifier rubyid_update!'>update!</span> <span class='label'>display_text:</span> <span class='id identifier rubyid_new_display_text'>new_display_text</span>
|
|
94
|
+
<span class='comment'># ... becomes ...
|
|
95
|
+
</span><span class='const'>Role</span><span class='lbracket'>[</span><span class='id identifier rubyid_name'>name</span><span class='rbracket'>]</span> <span class='op'>=</span> <span class='id identifier rubyid_new_display_text'>new_display_text</span>
|
|
96
|
+
|
|
97
|
+
</code></pre>
|
|
98
|
+
<p>Importantly, note that <strong>this gem works on the model, not its relations</strong>. ActiveRecord's existing bracket constructs for referencing <em>relations</em> (i.e. resultsets) in an <code>Array</code>-like fashion will continue to work as they always have.</p>
|
|
99
|
+
<h2 id="Installation">Installation</h2>
|
|
100
|
+
<ul>
|
|
101
|
+
<li>
|
|
102
|
+
<p>If your project uses <a href="https://github.com/bundler/bundler">Bundler</a>:</p>
|
|
103
|
+
<ul>
|
|
104
|
+
<li>Add one of the following to your application's Gemfile:
|
|
105
|
+
<pre class="code ruby"><code class="ruby"><span class='comment'># For on-demand usage:
|
|
106
|
+
</span>
|
|
107
|
+
<span class='id identifier rubyid_gem'>gem</span> <span class='tstring'><span class='tstring_beg'>'</span><span class='tstring_content'>activerecord-hashlike_access</span><span class='tstring_end'>'</span></span>
|
|
108
|
+
|
|
109
|
+
|
|
110
|
+
<span class='comment'># To automatically `extend ActiveRecord::HashlikeAccess`
|
|
111
|
+
</span><span class='comment'># into all your (`ActiveRecord::Base`-descended) models:
|
|
112
|
+
</span>
|
|
113
|
+
<span class='id identifier rubyid_gem'>gem</span> <span class='tstring'><span class='tstring_beg'>'</span><span class='tstring_content'>activerecord-hashlike_access</span><span class='tstring_end'>'</span></span><span class='comma'>,</span> <span class='label'>require:</span> <span class='tstring'><span class='tstring_beg'>'</span><span class='tstring_content'>active_record/hashlike_access/auto_extend</span><span class='tstring_end'>'</span></span>
|
|
114
|
+
</code></pre>
|
|
115
|
+
</li>
|
|
116
|
+
<li>And then run a:
|
|
117
|
+
<pre class="code shell"><code class="shell">$ bundle install
|
|
118
|
+
</code></pre>
|
|
119
|
+
</li>
|
|
120
|
+
</ul>
|
|
121
|
+
</li>
|
|
122
|
+
<li>
|
|
123
|
+
<p>Or, you can keep things simple with a manual install:</p>
|
|
124
|
+
<pre class="code shell"><code class="shell">$ gem install activerecord-hashlike_access
|
|
125
|
+
</code></pre>
|
|
126
|
+
</li>
|
|
127
|
+
</ul>
|
|
128
|
+
<h2 id="Usage">Usage</h2>
|
|
129
|
+
<p>Incorporating the <code>ActiveRecord::HashlikeAccess</code> module into a model will allow you to access it by a hash-like syntax, with the entrypoints for defining <em>what</em> you would like access to and <em>how</em> you would like to access it being the <code>hashlike_access</code> and <code>hashlike_access!</code> methods.</p>
|
|
130
|
+
<p>These two methods are nearly identical, the only difference being that a <code>hashlike_access</code> lookup that finds no matching records will return a <code>nil</code> (similar to ActiveRecord's <code>find_by</code>), whereas a failed <code>hashlike_access!</code> lookup will instead <code>raise ActiveRecord::RecordNotFound</code> (as a <code>find_by!</code> would).</p>
|
|
131
|
+
<p><code>hashlike_access</code>/<code>hashlike_access!</code> take two arguments:</p>
|
|
132
|
+
<ul>
|
|
133
|
+
<li><code>to</code> (optional): the field (or <em>arity-0</em> method) whose value you would like to get back for hash-like lookups; if omitted, the full record is returned</li>
|
|
134
|
+
<li><code>by</code> (optional): the field by which you would like to find matching records; if omitted, the model's primary key is used</li>
|
|
135
|
+
</ul>
|
|
136
|
+
<p>If your model pulls from <code>ActiveRecord::HashlikeAccess</code> but does not explicitly call one of these methods, the default behaviour will grant you hash-like access to records by the model's primary key.</p>
|
|
137
|
+
<h3 id="Hash_Like_Access_to__Records_">Hash-Like Access to <em>Records</em></h3>
|
|
138
|
+
<pre class="code ruby"><code class="ruby"><span class='kw'>class</span> <span class='const'>YourModel</span> <span class='op'><</span> <span class='const'>ApplicationRecord</span>
|
|
139
|
+
<span class='id identifier rubyid_extend'>extend</span> <span class='const'><span class='object_link'><a href="ActiveRecord.html" title="ActiveRecord (module)">ActiveRecord</a></span></span><span class='op'>::</span><span class='const'><span class='object_link'><a href="ActiveRecord/HashlikeAccess.html" title="ActiveRecord::HashlikeAccess (module)">HashlikeAccess</a></span></span>
|
|
140
|
+
|
|
141
|
+
<span class='comment'># For implicit access to records BY the primary key,
|
|
142
|
+
</span> <span class='comment'># you can omit the `hashlike_access` call altogether.
|
|
143
|
+
</span>
|
|
144
|
+
<span class='comment'># ...
|
|
145
|
+
</span>
|
|
146
|
+
|
|
147
|
+
<span class='comment'># For explicit access to records BY the primary key,
|
|
148
|
+
</span> <span class='comment'># call `hashlike_access` while omitting the `to` option:
|
|
149
|
+
</span>
|
|
150
|
+
<span class='id identifier rubyid_hashlike_access'>hashlike_access</span> <span class='label'>by:</span> <span class='id identifier rubyid_primary_key'>primary_key</span>
|
|
151
|
+
|
|
152
|
+
|
|
153
|
+
<span class='comment'># For access to records BY an arbitrary "lookup field",
|
|
154
|
+
</span> <span class='comment'># give `hashlike_access` the 'by' field and no 'to' option:
|
|
155
|
+
</span>
|
|
156
|
+
<span class='id identifier rubyid_hashlike_access'>hashlike_access</span> <span class='label'>by:</span> <span class='symbol'>:some_lookup_field_name</span>
|
|
157
|
+
|
|
158
|
+
<span class='kw'>end</span>
|
|
159
|
+
</code></pre>
|
|
160
|
+
<p>Any of the above options will make hash-like access (<code>YourModel[some_value]</code>) equivalent to a <code>find_by</code> (or a <code>find_by!</code>, in the case of <code>hashlike_access!</code>) using the requested field, resulting in:</p>
|
|
161
|
+
<ul>
|
|
162
|
+
<li>the matching record, if one is found</li>
|
|
163
|
+
<li>a <code>nil</code> value, in the case of <code>hashlike_access</code></li>
|
|
164
|
+
<li>an <code>ActiveRecord::RecordNotFound</code> error, in the case of <code>hashlike_access!</code></li>
|
|
165
|
+
</ul>
|
|
166
|
+
<h3 id="Hash_Like_Access_to__Values_">Hash-Like Access to <em>Values</em></h3>
|
|
167
|
+
<pre class="code ruby"><code class="ruby"><span class='kw'>class</span> <span class='const'>YourModel</span> <span class='op'><</span> <span class='const'>ApplicationRecord</span>
|
|
168
|
+
<span class='id identifier rubyid_extend'>extend</span> <span class='const'><span class='object_link'><a href="ActiveRecord.html" title="ActiveRecord (module)">ActiveRecord</a></span></span><span class='op'>::</span><span class='const'><span class='object_link'><a href="ActiveRecord/HashlikeAccess.html" title="ActiveRecord::HashlikeAccess (module)">HashlikeAccess</a></span></span>
|
|
169
|
+
|
|
170
|
+
<span class='comment'># For access TO a specific value for records matched BY the primary key,
|
|
171
|
+
</span> <span class='comment'># `hashlike_access` needs the target name via 'to', but the 'by' is optional:
|
|
172
|
+
</span>
|
|
173
|
+
<span class='id identifier rubyid_hashlike_access'>hashlike_access</span> <span class='label'>to:</span> <span class='symbol'>:field_or_method_name</span>
|
|
174
|
+
<span class='comment'># ... or ...
|
|
175
|
+
</span> <span class='id identifier rubyid_hashlike_access'>hashlike_access</span> <span class='label'>to:</span> <span class='symbol'>:field_or_method_name</span><span class='comma'>,</span> <span class='label'>by:</span> <span class='id identifier rubyid_primary_key'>primary_key</span>
|
|
176
|
+
|
|
177
|
+
|
|
178
|
+
<span class='comment'># For access TO a specific value BY an arbitrary "lookup field",
|
|
179
|
+
</span> <span class='comment'># give `hashlike_access` both the 'to' target and the 'by' field:
|
|
180
|
+
</span>
|
|
181
|
+
<span class='id identifier rubyid_hashlike_access'>hashlike_access</span> <span class='label'>to:</span> <span class='symbol'>:field_or_method_name</span><span class='comma'>,</span> <span class='label'>by:</span> <span class='symbol'>:some_lookup_field_name</span>
|
|
182
|
+
|
|
183
|
+
<span class='kw'>end</span>
|
|
184
|
+
</code></pre>
|
|
185
|
+
<p>Any of the above options will make hash-like access (<code>YourModel[some_value]</code>) equivalent to a <code>find_by</code>/<code>find_by!</code> followed by the requested method call. As with record lookups: if no matching record is found, expect a <code>nil</code> value or an <code>ActiveRecord::RecordNotFound</code> error, depending on whether you use <code>hashlike_access</code> or <code>hashlike_access!</code>.</p>
|
|
186
|
+
<h3 id="Hash_Like_Assignment_to__Values_">Hash-Like Assignment to <em>Values</em></h3>
|
|
187
|
+
<p>Requesting hash-like access to a value (<a href="#hash-like-access-to-values">see above</a>) also makes hash-like <em>assignment</em> (<code>[]=</code>) available <strong>provided that makes sense</strong>, i.e.:</p>
|
|
188
|
+
<ul>
|
|
189
|
+
<li>
|
|
190
|
+
<p>You have hash-like access to a field and the model is not read-only:</p>
|
|
191
|
+
<pre class="code ruby"><code class="ruby"><span class='kw'>class</span> <span class='const'>YourModel</span> <span class='op'><</span> <span class='const'>ApplicationRecord</span>
|
|
192
|
+
<span class='id identifier rubyid_extend'>extend</span> <span class='const'><span class='object_link'><a href="ActiveRecord.html" title="ActiveRecord (module)">ActiveRecord</a></span></span><span class='op'>::</span><span class='const'><span class='object_link'><a href="ActiveRecord/HashlikeAccess.html" title="ActiveRecord::HashlikeAccess (module)">HashlikeAccess</a></span></span>
|
|
193
|
+
<span class='id identifier rubyid_hashlike_access'>hashlike_access</span> <span class='label'>to:</span> <span class='symbol'>:field_x</span>
|
|
194
|
+
<span class='kw'>end</span>
|
|
195
|
+
|
|
196
|
+
<span class='comment'># Getting a value:
|
|
197
|
+
</span><span class='id identifier rubyid_field_x'>field_x</span> <span class='op'>=</span> <span class='const'>YourModel</span><span class='lbracket'>[</span><span class='id identifier rubyid_some_key'>some_key</span><span class='rbracket'>]</span>
|
|
198
|
+
|
|
199
|
+
<span class='comment'># Setting a value:
|
|
200
|
+
</span><span class='const'>YourModel</span><span class='lbracket'>[</span><span class='id identifier rubyid_some_key'>some_key</span><span class='rbracket'>]</span> <span class='op'>=</span> <span class='id identifier rubyid_new_value_for_field_x'>new_value_for_field_x</span>
|
|
201
|
+
</code></pre>
|
|
202
|
+
</li>
|
|
203
|
+
<li>
|
|
204
|
+
<p>You have hash-like access to a method and there is <em>also</em> a corresponding <code>=</code> method for it:</p>
|
|
205
|
+
<pre class="code ruby"><code class="ruby"><span class='kw'>class</span> <span class='const'>YourModel</span> <span class='op'><</span> <span class='const'>ApplicationRecord</span>
|
|
206
|
+
<span class='id identifier rubyid_extend'>extend</span> <span class='const'><span class='object_link'><a href="ActiveRecord.html" title="ActiveRecord (module)">ActiveRecord</a></span></span><span class='op'>::</span><span class='const'><span class='object_link'><a href="ActiveRecord/HashlikeAccess.html" title="ActiveRecord::HashlikeAccess (module)">HashlikeAccess</a></span></span>
|
|
207
|
+
<span class='id identifier rubyid_hashlike_access'>hashlike_access</span> <span class='label'>to:</span> <span class='symbol'>:method_x</span>
|
|
208
|
+
|
|
209
|
+
<span class='kw'>def</span> <span class='id identifier rubyid_method_x'>method_x</span>
|
|
210
|
+
<span class='comment'># ...
|
|
211
|
+
</span> <span class='kw'>end</span>
|
|
212
|
+
|
|
213
|
+
<span class='kw'>def</span> <span class='id identifier rubyid_method_x='>method_x=</span><span class='lparen'>(</span><span class='id identifier rubyid_value'>value</span><span class='rparen'>)</span>
|
|
214
|
+
<span class='comment'># ...
|
|
215
|
+
</span> <span class='kw'>end</span>
|
|
216
|
+
<span class='kw'>end</span>
|
|
217
|
+
|
|
218
|
+
<span class='comment'># Getting a value:
|
|
219
|
+
</span><span class='id identifier rubyid_method_x'>method_x</span> <span class='op'>=</span> <span class='const'>YourModel</span><span class='lbracket'>[</span><span class='id identifier rubyid_some_key'>some_key</span><span class='rbracket'>]</span>
|
|
220
|
+
|
|
221
|
+
<span class='comment'># Setting a value:
|
|
222
|
+
</span><span class='const'>YourModel</span><span class='lbracket'>[</span><span class='id identifier rubyid_some_key'>some_key</span><span class='rbracket'>]</span> <span class='op'>=</span> <span class='id identifier rubyid_value_to_pass_to_method_x_assignment'>value_to_pass_to_method_x_assignment</span>
|
|
223
|
+
</code></pre>
|
|
224
|
+
<p>If you attempt a hash-like value assignment and the requisite assignment method has not been defined, a <code>NoMethodError</code> will be raised.</p>
|
|
225
|
+
</li>
|
|
226
|
+
</ul>
|
|
227
|
+
<p>Note hash-like value assignments are backed by an <code>update!</code> call, which will:</p>
|
|
228
|
+
<ul>
|
|
229
|
+
<li>run validations, possibly raising an <code>ActiveRecord::RecordInvalid</code> error</li>
|
|
230
|
+
<li>trigger callbacks, possibly raising an <code>ActiveRecord::RecordNotSaved</code> error</li>
|
|
231
|
+
<li>update timestamps</li>
|
|
232
|
+
</ul>
|
|
233
|
+
<h3 id="Using_Non_Scalar_Keys">Using Non-Scalar Keys</h3>
|
|
234
|
+
<p>If your model uses a composite primary key, hash-like access happens by passing all the needed values:</p>
|
|
235
|
+
<pre class="code ruby"><code class="ruby"><span class='kw'>class</span> <span class='const'>YourModel</span> <span class='op'><</span> <span class='const'>ApplicationRecord</span>
|
|
236
|
+
<span class='id identifier rubyid_extend'>extend</span> <span class='const'><span class='object_link'><a href="ActiveRecord.html" title="ActiveRecord (module)">ActiveRecord</a></span></span><span class='op'>::</span><span class='const'><span class='object_link'><a href="ActiveRecord/HashlikeAccess.html" title="ActiveRecord::HashlikeAccess (module)">HashlikeAccess</a></span></span>
|
|
237
|
+
<span class='kw'>self</span><span class='period'>.</span><span class='id identifier rubyid_primary_key'>primary_key</span> <span class='op'>=</span> <span class='lbracket'>[</span><span class='symbol'>:primary_key_1</span><span class='comma'>,</span> <span class='symbol'>:primary_key_2</span><span class='rbracket'>]</span>
|
|
238
|
+
<span class='kw'>end</span>
|
|
239
|
+
|
|
240
|
+
|
|
241
|
+
<span class='comment'># You need to provide as many key values
|
|
242
|
+
</span><span class='comment'># as there are fields in the primary key:
|
|
243
|
+
</span>
|
|
244
|
+
<span class='id identifier rubyid_record'>record</span> <span class='op'>=</span> <span class='const'>YourModel</span><span class='lbracket'>[</span><span class='int'>1</span><span class='comma'>,</span> <span class='int'>2</span><span class='rbracket'>]</span>
|
|
245
|
+
<span class='comment'># ... or if you have an array:
|
|
246
|
+
</span><span class='id identifier rubyid_record'>record</span> <span class='op'>=</span> <span class='const'>YourModel</span><span class='lbracket'>[</span><span class='op'>*</span><span class='id identifier rubyid_key_values'>key_values</span><span class='rbracket'>]</span>
|
|
247
|
+
</code></pre>
|
|
248
|
+
<p>You can also do this if you want to use multiple non-primary-key lookup fields by passing an array to the <code>by</code> option:</p>
|
|
249
|
+
<pre class="code ruby"><code class="ruby"><span class='kw'>class</span> <span class='const'>YourModel</span> <span class='op'><</span> <span class='const'>ApplicationRecord</span>
|
|
250
|
+
<span class='id identifier rubyid_extend'>extend</span> <span class='const'><span class='object_link'><a href="ActiveRecord.html" title="ActiveRecord (module)">ActiveRecord</a></span></span><span class='op'>::</span><span class='const'><span class='object_link'><a href="ActiveRecord/HashlikeAccess.html" title="ActiveRecord::HashlikeAccess (module)">HashlikeAccess</a></span></span>
|
|
251
|
+
<span class='id identifier rubyid_hashlike_access'>hashlike_access</span> <span class='label'>by:</span> <span class='lbracket'>[</span><span class='symbol'>:lookup_field_1</span><span class='comma'>,</span> <span class='symbol'>:lookup_field_2</span><span class='rbracket'>]</span>
|
|
252
|
+
<span class='kw'>end</span>
|
|
253
|
+
|
|
254
|
+
|
|
255
|
+
<span class='comment'># You need to provide as many key values
|
|
256
|
+
</span><span class='comment'># as there were fields in the "by" option:
|
|
257
|
+
</span>
|
|
258
|
+
<span class='id identifier rubyid_record'>record</span> <span class='op'>=</span> <span class='const'>YourModel</span><span class='lbracket'>[</span><span class='int'>1</span><span class='comma'>,</span> <span class='int'>2</span><span class='rbracket'>]</span>
|
|
259
|
+
<span class='comment'># ... or if you have an array:
|
|
260
|
+
</span><span class='id identifier rubyid_record'>record</span> <span class='op'>=</span> <span class='const'>YourModel</span><span class='lbracket'>[</span><span class='op'>*</span><span class='id identifier rubyid_lookup_values'>lookup_values</span><span class='rbracket'>]</span>
|
|
261
|
+
</code></pre>
|
|
262
|
+
<h2 id="Performance_Considerations">Performance Considerations</h2>
|
|
263
|
+
<p>Every instance of a hash-like lookup (<code>[some_key]</code>) is backed by a <code>find_by</code>/<code>find_by!</code> call, but ActiveRecord's query cache goes <em>a long way</em> to reducing the performance penalty from repeated calls for the same record within a single worker.</p>
|
|
264
|
+
<h2 id="Potential_Gotchas">Potential Gotchas</h2>
|
|
265
|
+
<p>As with anything ActiveRecord-related, there are always several ways to shoot yourself in the foot if you're not careful. Here are a few items to keep in mind and hopefully prevent this:</p>
|
|
266
|
+
<ul>
|
|
267
|
+
<li>
|
|
268
|
+
<p>The hash-like access construct is essentially syntax sugar around ActiveRecord's <code>find_by</code> mechanism. For many (most?) database engines, selecting (or <em>including</em>, in the case of a multi-field key) an unindexed field for your lookups will likely result in a full-table scan with every hash-like access. Be mindful of what field(s) you're using as your key(s).</p>
|
|
269
|
+
</li>
|
|
270
|
+
<li>
|
|
271
|
+
<p>Selecting a lookup field with non-unique values means the matching record you get back is non-deterministic <em>unless you take precautions to avoid this</em> (e.g. by setting a default scope with an <code>order</code> on fields that yield a unique combination of values). This should go without saying, but: maybe don't use a non-unique field to try to find a specific record?</p>
|
|
272
|
+
</li>
|
|
273
|
+
</ul>
|
|
274
|
+
<h2 id="Contribution___Development">Contribution / Development</h2>
|
|
275
|
+
<p>Bug reports and pull requests are welcome at: <a href="https://github.com/nestor-custodio/activerecord-hashlike_access"><a href="https://github.com/nestor-custodio/activerecord-hashlike_access">https://github.com/nestor-custodio/activerecord-hashlike_access</a></a></p>
|
|
276
|
+
<p>After checking out the repo, run <code>bin/setup</code> to install dependencies. Then, run <code>rake spec</code> to run the tests. You can also run <code>bin/console</code> for an interactive prompt that will allow you to experiment.</p>
|
|
277
|
+
<p>Linting is courtesy of <a href="https://docs.rubocop.org/">Rubocop</a> (<code>rake rubocop</code>) and documentation is built using <a href="https://yardoc.org/">YARD</a>. Please ensure you have a clean bill of health from Rubocop and that any new features and/or changes to behaviour are reflected in the adjacent documentation before submitting a pull request.</p>
|
|
278
|
+
<h2 id="License">License</h2>
|
|
279
|
+
<p><code>ActiveRecord::HashlikeAccess</code> is available as open source under the terms of the <a href="https://tldrlegal.com/license/mit-license">MIT License</a>.</p></div></div>
|
|
280
|
+
|
|
281
|
+
<div id="footer">
|
|
282
|
+
Generated on Tue Aug 18 18:42:26 2026 by
|
|
283
|
+
<a href="https://yardoc.org" title="Yay! A Ruby Documentation Tool" target="_parent">yard</a>
|
|
284
|
+
0.9.45 (ruby-3.4.8).
|
|
285
|
+
</div>
|
|
286
|
+
|
|
287
|
+
</div>
|
|
288
|
+
</body>
|
|
289
|
+
</html>
|
data/docs/file_list.html
ADDED
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
<!DOCTYPE html>
|
|
2
|
+
<html >
|
|
3
|
+
<head>
|
|
4
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
5
|
+
<meta charset="utf-8">
|
|
6
|
+
|
|
7
|
+
<link rel="stylesheet" href="css/full_list.css" type="text/css" media="screen">
|
|
8
|
+
|
|
9
|
+
<link rel="stylesheet" href="css/common.css" type="text/css" media="screen">
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
<script type="text/javascript" charset="utf-8" src="js/jquery.js"></script>
|
|
14
|
+
|
|
15
|
+
<script type="text/javascript" charset="utf-8" src="js/full_list.js"></script>
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
<title>File List</title>
|
|
19
|
+
<base id="base_target" target="_parent">
|
|
20
|
+
</head>
|
|
21
|
+
<body>
|
|
22
|
+
<div id="content">
|
|
23
|
+
<div class="fixed_header">
|
|
24
|
+
<h1 id="full_list_header">File List</h1>
|
|
25
|
+
<div id="full_list_nav">
|
|
26
|
+
|
|
27
|
+
<span><a target="_self" href="class_list.html">
|
|
28
|
+
Classes
|
|
29
|
+
</a></span>
|
|
30
|
+
|
|
31
|
+
<span><a target="_self" href="method_list.html">
|
|
32
|
+
Methods
|
|
33
|
+
</a></span>
|
|
34
|
+
|
|
35
|
+
<span><a target="_self" href="file_list.html">
|
|
36
|
+
Files
|
|
37
|
+
</a></span>
|
|
38
|
+
|
|
39
|
+
</div>
|
|
40
|
+
|
|
41
|
+
<div id="search">
|
|
42
|
+
<label for="search-class">Search:</label>
|
|
43
|
+
<input id="search-class" type="text">
|
|
44
|
+
</div>
|
|
45
|
+
</div>
|
|
46
|
+
|
|
47
|
+
<ul id="full_list" class="file">
|
|
48
|
+
|
|
49
|
+
|
|
50
|
+
<li id="object_README" class="odd">
|
|
51
|
+
<div class="item"><span class="object_link"><a href="index.html" title="README">README</a></span></div>
|
|
52
|
+
</li>
|
|
53
|
+
|
|
54
|
+
|
|
55
|
+
|
|
56
|
+
</ul>
|
|
57
|
+
</div>
|
|
58
|
+
</body>
|
|
59
|
+
</html>
|
data/docs/frames.html
ADDED
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
<!DOCTYPE html>
|
|
2
|
+
<html>
|
|
3
|
+
<head>
|
|
4
|
+
<meta charset="utf-8">
|
|
5
|
+
<title>Documentation by YARD 0.9.45</title>
|
|
6
|
+
</head>
|
|
7
|
+
<script type="text/javascript">
|
|
8
|
+
var mainUrl = 'index.html';
|
|
9
|
+
try {
|
|
10
|
+
var match = decodeURIComponent(window.location.hash).match(/^#!(.+)/);
|
|
11
|
+
var name = match ? match[1] : mainUrl;
|
|
12
|
+
var url = new URL(name, location.href);
|
|
13
|
+
window.top.location.replace(url.origin === location.origin ? name : mainUrl);
|
|
14
|
+
} catch (e) {
|
|
15
|
+
window.top.location.replace(mainUrl);
|
|
16
|
+
}
|
|
17
|
+
</script>
|
|
18
|
+
<noscript>
|
|
19
|
+
<h1>Oops!</h1>
|
|
20
|
+
<h2>YARD requires JavaScript!</h2>
|
|
21
|
+
</noscript>
|
|
22
|
+
</html>
|