forked from justin808/justin808.github.io
-
Notifications
You must be signed in to change notification settings - Fork 0
/
index.html
5914 lines (5131 loc) · 302 KB
/
index.html
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
<!DOCTYPE html>
<!--[if IEMobile 7 ]><html class="no-js iem7"><![endif]-->
<!--[if lt IE 9]><html class="no-js lte-ie8"><![endif]-->
<!--[if (gt IE 8)|(gt IEMobile 7)|!(IEMobile)|!(IE)]><!--><html class="no-js" lang="en"><!--<![endif]-->
<head>
<meta charset="utf-8">
<title>Rails on Maui</title>
<meta name="author" content="Justin Gordon">
<meta name="description" content="Sometimes when you get puzzled by what Rails is doing, you really just need to
understand what Ruby is doing. For example, given this simple code to …">
<!-- http://t.co/dKP3o1e -->
<meta name="HandheldFriendly" content="True">
<meta name="MobileOptimized" content="320">
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="canonical" href="http://www.railsonmaui.com">
<link href="/railsonmaui-favicon.ico" rel="icon">
<link href="/stylesheets/screen.css" media="screen, projection" rel="stylesheet" type="text/css">
<link href="http://feeds.feedburner.com/railsonmaui" rel="alternate" title="Rails on Maui" type="application/atom+xml">
<script src="/javascripts/modernizr-2.0.js"></script>
<script src="//ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script>
<script>!window.jQuery && document.write(unescape('%3Cscript src="./javascripts/libs/jquery.min.js"%3E%3C/script%3E'))</script>
<script src="/javascripts/octopress.js" type="text/javascript"></script>
<!--Fonts from Google"s Web font directory at http://google.com/webfonts -->
<link href="http://fonts.googleapis.com/css?family=PT+Serif:regular,italic,bold,bolditalic" rel="stylesheet" type="text/css">
<link href="http://fonts.googleapis.com/css?family=PT+Sans:regular,italic,bold,bolditalic" rel="stylesheet" type="text/css">
<script type="text/javascript">
var _gaq = _gaq || [];
_gaq.push(['_setAccount', 'UA-40522944-1']);
_gaq.push(['_trackPageview']);
(function() {
var ga = document.createElement('script'); ga.type = 'text/javascript'; ga.async = true;
ga.src = ('https:' == document.location.protocol ? 'https://ssl' : 'http://www') + '.google-analytics.com/ga.js';
var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(ga, s);
})();
</script>
</head>
<body >
<header role="banner"><hgroup>
<h1><a href="/">Rails on Maui</a></h1>
<h2>Programming in Paradise</h2>
</hgroup>
</header>
<nav role="navigation"><ul class="subscription" data-subscription="rss email">
<li><a href="http://feeds.feedburner.com/railsonmaui" rel="subscribe-rss" title="subscribe via RSS">RSS</a></li>
<li><a href="http://feedburner.google.com/fb/a/mailverify?uri=RailsOnMaui&loc=en_US" rel="subscribe-email" title="subscribe via email">Email</a></li>
</ul>
<form action="http://google.com/search" method="get">
<fieldset role="search">
<input type="hidden" name="q" value="site:www.railsonmaui.com/" />
<input class="search" type="text" name="q" results="0" placeholder="Search"/>
</fieldset>
</form>
<ul class="main-navigation">
<li><a href="/">Blog</a></li>
<li><a href="/blog/archives/">Archives</a></li>
<li><a href="/blog/categories.html">Categories</a></li>
<li><a href="/tips/">Tips</a></li>
<li><a href="/meta/">Meta</a></li>
<li><a href="/about/">About</a></li>
<li><a href="http://forum.railsonmaui.com">Forum</a></li>
</ul>
</nav>
<div id="main">
<div id="content">
<div class="blog-index">
<article>
<header>
<h1 class="entry-title"><a href="/blog/2014/10/22/enums-and-queries-in-rails-4-dot-1/">Enums and Queries in Rails 4.1, and Understanding Ruby</a></h1>
<p class="meta">
<time class='entry-date' datetime='2014-10-22T19:23:02-10:00'><span class='date'><span class='date-month'>Oct</span> <span class='date-day'>22</span><span class='date-suffix'>nd</span>, <span class='date-year'>2014</span></span> <span class='time'>7:23 pm</span></time>
</p>
</header>
<div class="entry-content"><p>
Sometimes when you get puzzled by what Rails is doing, you really just need to
understand what Ruby is doing.
</p>
<p>
For example, given this simple code to get an attribute value:
</p>
<figure class='code'><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
</pre></td><td class='code'><pre><code class='ruby'><span class='line'><span class="c1"># return value of some_attribute and foobar</span>
</span><span class='line'><span class="k">def</span> <span class="nf">some_attribute_foobar</span>
</span><span class='line'> <span class="s2">"</span><span class="si">#{</span><span class="n">some_attribute</span><span class="si">}</span><span class="s2"> and foobar"</span>
</span><span class='line'><span class="k">end</span>
</span></code></pre></td></tr></table></div></figure>
<p>
Beginners are often stumped by why this code does not set an attribute value:
</p>
<figure class='code'><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
</pre></td><td class='code'><pre><code class='ruby'><span class='line'><span class="c1"># change the value of some_attribute to foobar</span>
</span><span class='line'><span class="k">def</span> <span class="nf">change_some_attribute</span>
</span><span class='line'> <span class="c1"># why doesn't the next line set the some_attribute value to "foobar"?</span>
</span><span class='line'> <span class="n">some_attribute</span> <span class="o">=</span> <span class="s2">"foobar"</span>
</span><span class='line'> <span class="n">save!</span>
</span><span class='line'><span class="k">end</span>
</span></code></pre></td></tr></table></div></figure>
<p>
What’s going on?
</p>
<p>
In the first method, <code>some_attribute</code> is actually a method call which gets the
attribute value of the record. This works in Rails ActiveRecord due to the Ruby
feature of <a href="http://www.ruby-doc.org/core-2.1.3/BasicObject.html">method_missing</a> which allows some code to run when a method is called
that does not exist.
</p>
<p>
In the second method, a local variable called some_attribute is getting
assigned. There is no call to method_missing, as this is a variable assignment!
</p>
<p>
The correct code should have been:
</p>
<figure class='code'><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
</pre></td><td class='code'><pre><code class='ruby'><span class='line'><span class="c1"># change the value of some_attribute to foobar</span>
</span><span class='line'><span class="k">def</span> <span class="nf">change_some_attribute</span>
</span><span class='line'> <span class="nb">self</span><span class="o">.</span><span class="n">some_attribute</span> <span class="o">=</span> <span class="s2">"foobar"</span>
</span><span class='line'> <span class="n">save!</span>
</span><span class='line'><span class="k">end</span>
</span></code></pre></td></tr></table></div></figure>
<p>
In this case, we’re calling the method <code>some_attribute=</code> on the model instance,
and we get the expected result of assigning an attribute value.
</p>
<div id="outline-container-sec-1" class="outline-2">
<h2 id="sec-1">Enums</h2>
<div class="outline-text-2" id="text-1">
<p>
For those not familiar with enums:
</p>
<blockquote>
<p>
An enum type is a special data type that enables for a variable to be a set of
predefined constants. The variable must be equal to one of the values that have
been predefined for it.
</p>
</blockquote>
<p>
Enums, introduced in Rails 4.1, are a place a lot of Ruby magic happens! It’s
critical to understand Ruby well in order to understand how to use enums
effectively. Let’s suppose we have this simple example, copied over from the
<a href="http://edgeapi.rubyonrails.org/classes/ActiveRecord/Enum.html">Rails docs</a>:
</p>
<figure class='code'><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
<span class='line-number'>7</span>
<span class='line-number'>8</span>
<span class='line-number'>9</span>
<span class='line-number'>10</span>
<span class='line-number'>11</span>
<span class='line-number'>12</span>
<span class='line-number'>13</span>
<span class='line-number'>14</span>
<span class='line-number'>15</span>
<span class='line-number'>16</span>
<span class='line-number'>17</span>
<span class='line-number'>18</span>
<span class='line-number'>19</span>
<span class='line-number'>20</span>
<span class='line-number'>21</span>
</pre></td><td class='code'><pre><code class='ruby'><span class='line'><span class="k">class</span> <span class="nc">Conversation</span> <span class="o"><</span> <span class="no">ActiveRecord</span><span class="o">::</span><span class="no">Base</span>
</span><span class='line'> <span class="n">enum</span> <span class="ss">status</span><span class="p">:</span> <span class="o">[</span> <span class="ss">:active</span><span class="p">,</span> <span class="ss">:archived</span> <span class="o">]</span>
</span><span class='line'><span class="k">end</span>
</span><span class='line'>
</span><span class='line'><span class="c1"># conversation.update! status: 0</span>
</span><span class='line'><span class="n">conversation</span><span class="o">.</span><span class="n">active!</span>
</span><span class='line'><span class="n">conversation</span><span class="o">.</span><span class="n">active?</span> <span class="c1"># => true</span>
</span><span class='line'><span class="n">conversation</span><span class="o">.</span><span class="n">status</span> <span class="c1"># => "active"</span>
</span><span class='line'>
</span><span class='line'><span class="c1"># conversation.update! status: 1</span>
</span><span class='line'><span class="n">conversation</span><span class="o">.</span><span class="n">archived!</span>
</span><span class='line'><span class="n">conversation</span><span class="o">.</span><span class="n">archived?</span> <span class="c1"># => true</span>
</span><span class='line'><span class="n">conversation</span><span class="o">.</span><span class="n">status</span> <span class="c1"># => "archived"</span>
</span><span class='line'>
</span><span class='line'><span class="c1"># conversation.update! status: 1</span>
</span><span class='line'><span class="n">conversation</span><span class="o">.</span><span class="n">status</span> <span class="o">=</span> <span class="s2">"archived"</span>
</span><span class='line'>
</span><span class='line'><span class="c1"># conversation.update! status: nil</span>
</span><span class='line'><span class="n">conversation</span><span class="o">.</span><span class="n">status</span> <span class="o">=</span> <span class="kp">nil</span>
</span><span class='line'><span class="n">conversation</span><span class="o">.</span><span class="n">status</span><span class="o">.</span><span class="n">nil?</span> <span class="c1"># => true</span>
</span><span class='line'><span class="n">conversation</span><span class="o">.</span><span class="n">status</span> <span class="c1"># => nil</span>
</span></code></pre></td></tr></table></div></figure>
<p>
So what’s going on in terms of Ruby meta-programming?
</p>
<p>
For all the enum values declared for <code>Conversation</code>, methods are created in the
following forms. Let’s use the model Conversation, column “status”, and the enum “active” for this exampl:
</p>
<table border="2" cellspacing="0" cellpadding="6" rules="groups" frame="hsides">
<colgroup>
<col class="left" />
<col class="left" />
</colgroup>
<thead>
<tr>
<th scope="col" class="left">method</th>
<th scope="col" class="left">description</th>
</tr>
</thead>
<tbody>
<tr>
<td class="left"><code>self.status</code></td>
<td class="left">Returns enum <b>string</b> value (not symbol, and not <b>integer</b> db value)</td>
</tr>
<tr>
<td class="left"><code>self.status=<enum_string_value or integer_value></code></td>
<td class="left">Set the status to corresponding enum integer value using either a string, symbol, or integer. If you use an invalid value, you get an ArgumentError. String/symbol is converted to corresponding integer value.</td>
</tr>
<tr>
<td class="left"><code>self.active!</code></td>
<td class="left">Sets the status enum to “active”. This syntax is a bit confusing in that you don’t see the attribute you’re assigning! ArgumentError if invalid enum.</td>
</tr>
<tr>
<td class="left"><code>self.active?</code></td>
<td class="left">equivalent to (<code>self.status =</code> “active”<code>), and *not* equivalent to (=self.status =</code> :active=) due to symbols not being equal to strings!</td>
</tr>
<tr>
<td class="left"><code>Conversation.active</code></td>
<td class="left">equivalent to <code>Conversation.where(status: "active")</code>. Again, it’s a bit confusing not to see the column being queried.</td>
</tr>
<tr>
<td class="left"><code>Conversation.statuses</code></td>
<td class="left">Mapping of symbols to ordinal values <code>{ "active" \=> 0, "archived" \=> 1 }</code>, of type <code>HashWithIndifferentAccess</code>, meaning you can use symbols or strings</td>
</tr>
</tbody>
</table>
</div>
<div id="outline-container-sec-1-1" class="outline-3">
<h3 id="sec-1-1">Default Values for Enums</h3>
<div class="outline-text-3" id="text-1-1">
<p>
As the docs say, it’s a good idea to use the default value from the database declaration, like:
</p>
<figure class='code'><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
</pre></td><td class='code'><pre><code class='ruby'><span class='line'><span class="n">create_table</span> <span class="ss">:conversations</span> <span class="k">do</span> <span class="o">|</span><span class="n">t</span><span class="o">|</span>
</span><span class='line'> <span class="n">t</span><span class="o">.</span><span class="n">column</span> <span class="ss">:status</span><span class="p">,</span> <span class="ss">:integer</span><span class="p">,</span> <span class="ss">default</span><span class="p">:</span> <span class="mi">0</span><span class="p">,</span> <span class="ss">null</span><span class="p">:</span> <span class="kp">false</span>
</span><span class='line'><span class="k">end</span>
</span></code></pre></td></tr></table></div></figure>
<p>
More specifically, consider using the first declared status (enum db value zero)
be the default <i>and</i> to not allow null values. I’ve found that when I’ve allowed
null values in enums, it makes all my code more complicated. This is an example
of the <a href="http://robots.thoughtbot.com/rails-refactoring-example-introduce-null-object">Null Object Pattern</a>. Nulls in your data and checking for these in your
code will make your life more difficult! Instead, have an enum value for “I
don’t know” if that really is a possibility, and make that first value, which is
an index of zero, and you can set that as the database column default.
</p>
</div>
</div>
<div id="outline-container-sec-1-2" class="outline-3">
<h3 id="sec-1-2">Queries on Enums</h3>
<div class="outline-text-3" id="text-1-2">
<p>
The docs say:
</p>
<blockquote>
<p>
In rare circumstances you might need to access the mapping directly. The mappings are exposed through a class method with the pluralized attribute name
</p>
</blockquote>
<figure class='code'><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
</pre></td><td class='code'><pre><code class='ruby'><span class='line'><span class="no">Conversation</span><span class="o">.</span><span class="n">statuses</span> <span class="c1"># => { "active" => 0, "archived" => 1 }</span>
</span></code></pre></td></tr></table></div></figure>
<p>
<b>This is not rare! This is critical!</b>
</p>
<p>
For example, suppose you want to query where the status is not “archived”:
</p>
<p>
You might be tempted to think that Rails will be smart enough to figure out that
</p>
<figure class='code'><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
</pre></td><td class='code'><pre><code class='ruby'><span class='line'><span class="no">Conversation</span><span class="o">.</span><span class="n">where</span><span class="p">(</span><span class="s2">"status <> ?"</span><span class="p">,</span> <span class="s2">"archived"</span><span class="p">)</span>
</span></code></pre></td></tr></table></div></figure>
<p>
Rails is not smart enough to know that the ? is for status and that is an enum.
So you have to use this syntax:
</p>
<figure class='code'><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
</pre></td><td class='code'><pre><code class='ruby'><span class='line'><span class="no">Conversation</span><span class="o">.</span><span class="n">where</span><span class="p">(</span><span class="s2">"status <> ?"</span><span class="p">,</span> <span class="no">Conversation</span><span class="o">.</span><span class="n">statuses</span><span class="o">[</span><span class="ss">:archived</span><span class="o">]</span><span class="p">)</span>
</span></code></pre></td></tr></table></div></figure>
<p>
You might be tempted to think that this would work:
</p>
<figure class='code'><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
</pre></td><td class='code'><pre><code class='ruby'><span class='line'><span class="no">Conversation</span><span class="o">.</span><span class="n">where</span><span class="o">.</span><span class="n">not</span><span class="p">(</span><span class="ss">status</span><span class="p">:</span> <span class="ss">:archived</span><span class="p">)</span>
</span></code></pre></td></tr></table></div></figure>
<p>
That throws an <code>ArgumentError</code>. Rails wants an integer and not a symbol, and symbol does
not define <code>to_i</code>.
</p>
<p>
What’s worse is this one:
</p>
<figure class='code'><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
</pre></td><td class='code'><pre><code class='ruby'><span class='line'><span class="no">Conversation</span><span class="o">.</span><span class="n">where</span><span class="o">.</span><span class="n">not</span><span class="p">(</span><span class="ss">status</span><span class="p">:</span> <span class="s2">"archived"</span><span class="p">)</span>
</span></code></pre></td></tr></table></div></figure>
<p>
The problem is that ActiveRecord sees that the enum column is of type integer
and calls <code>#to_i</code> on the value, so <code>archived.to_i</code> <b>gets converted to zero</b>. In
fact, <b>all your enums will get converted to zero!</b> And if you use the value of
the enum attribute on an ActiveRecord instance (say a Conversation object),
then you’re using a string value!
</p>
<p>
If you’re curious what the Rails source is, then take a look here: <a href="https://github.com/rails/rails/blob/master/activerecord/lib/active_record/type/integer.rb">ActiveRecord::Type::Integer</a>.
</p>
<p>
Here’s a guaranteed broken bit of code:
</p>
<figure class='code'><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
</pre></td><td class='code'><pre><code class='ruby'><span class='line'><span class="c1"># my_conversation.status is a String!</span>
</span><span class='line'><span class="no">Conversation</span><span class="o">.</span><span class="n">where</span><span class="o">.</span><span class="n">not</span><span class="p">(</span><span class="ss">status</span><span class="p">:</span> <span class="n">my_conversation</span><span class="o">.</span><span class="n">status</span><span class="p">)</span>
</span></code></pre></td></tr></table></div></figure>
<p>
You’d think that Rails would be clever enough to see that the key maps to an
enum and then check if the comparison value is a String, and then it would
<b>not</b> call <code>to_i</code> on the String! Instead, we are effectively running this code:
</p>
<figure class='code'><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
</pre></td><td class='code'><pre><code class='ruby'><span class='line'><span class="no">Conversation</span><span class="o">.</span><span class="n">where</span><span class="o">.</span><span class="n">not</span><span class="p">(</span><span class="ss">status</span><span class="p">:</span> <span class="mi">0</span><span class="p">)</span>
</span></code></pre></td></tr></table></div></figure>
<p>
An acceptable alternative to the last code example would be:
</p>
<figure class='code'><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
</pre></td><td class='code'><pre><code class='ruby'><span class='line'><span class="no">Conversation</span><span class="o">.</span><span class="n">where</span><span class="o">.</span><span class="n">not</span><span class="p">(</span><span class="no">Conersation</span><span class="o">.</span><span class="n">statuses</span><span class="o">[</span><span class="n">my_conversation</span><span class="o">.</span><span class="n">status</span><span class="o">]</span><span class="p">)</span>
</span></code></pre></td></tr></table></div></figure>
<p>
If you left out the <code>not</code>, you could also do:
</p>
<figure class='code'><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
</pre></td><td class='code'><pre><code class='ruby'><span class='line'><span class="no">Conversation</span><span class="o">.</span><span class="n">send</span><span class="p">(</span><span class="n">my_conversation</span><span class="o">.</span><span class="n">status</span><span class="p">)</span>
</span></code></pre></td></tr></table></div></figure>
<p>
However, I really would like to simply do these, <i>all of which <b>DO NOT</b> work</i>.:
</p>
<figure class='code'><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
</pre></td><td class='code'><pre><code class='ruby'><span class='line'><span class="no">Conversation</span><span class="o">.</span><span class="n">where</span><span class="p">(</span><span class="ss">status</span><span class="p">:</span> <span class="n">my_conversation</span><span class="o">.</span><span class="n">status</span><span class="p">)</span>
</span><span class='line'><span class="no">Conversation</span><span class="o">.</span><span class="n">where</span><span class="p">(</span><span class="ss">status</span><span class="p">:</span> <span class="ss">:archived</span><span class="p">)</span>
</span><span class='line'><span class="no">Conversation</span><span class="o">.</span><span class="n">where</span><span class="p">(</span><span class="ss">status</span><span class="p">:</span> <span class="s2">"archived"</span><span class="p">)</span>
</span></code></pre></td></tr></table></div></figure>
</div>
</div>
<div id="outline-container-sec-1-3" class="outline-3">
<h3 id="sec-1-3">Pluck vs Map with Enums</h3>
<div class="outline-text-3" id="text-1-3">
<p>
Here’s another subtle issue with enums.
</p>
<p>
Should these two lines of code give the same result or a different result:
</p>
<figure class='code'><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
</pre></td><td class='code'><pre><code class='ruby'><span class='line'><span class="n">statuses_with_map</span> <span class="o">=</span> <span class="no">Conversation</span><span class="o">.</span><span class="n">select</span><span class="p">(</span><span class="ss">:status</span><span class="p">)</span><span class="o">.</span><span class="n">where</span><span class="o">.</span><span class="n">not</span><span class="p">(</span><span class="ss">status</span><span class="p">:</span> <span class="kp">nil</span><span class="p">)</span><span class="o">.</span><span class="n">distinct</span><span class="o">.</span><span class="n">map</span><span class="p">(</span><span class="o">&</span><span class="ss">:status</span><span class="p">)</span>
</span><span class='line'><span class="n">statuses_with_pluck</span> <span class="o">=</span> <span class="no">Conversation</span><span class="o">.</span><span class="n">distinct</span><span class="o">.</span><span class="n">where</span><span class="o">.</span><span class="n">not</span><span class="p">(</span><span class="ss">status</span><span class="p">:</span> <span class="kp">nil</span><span class="p">)</span><span class="o">.</span><span class="n">pluck</span><span class="p">(</span><span class="ss">:status</span><span class="p">)</span>
</span></code></pre></td></tr></table></div></figure>
<p>
It’s worth experimenting with this in the <a href="http://www.railsonmaui.com/blog/2014/08/17/pry-ruby-and-fun-with-the-hash-constructor/">Pry console</a>!
</p>
<p>
In the first case, with <code>map</code>, you get back an Array with 2 strings: <code>["active",
"archived"]</code>. In the second case, with <code>pluck</code>, you get back an Array with 2
integers: <code>[0, 1]</code>.
</p>
<p>
What’s going on here?
</p>
<p>
In the code where <code>map</code> calls the <code>status</code> method on each <code>Conversation</code> record,
the <code>status</code> method converts the database integer value into the corresponding
String value!
</p>
<p>
In the other code that uses <code>:pluck</code>, you get back the raw database value. It’s
arguable whether or not Rails should intelligently transform this value into the
string equivalent, since that is what is done in other uses of ActiveRecord.
Changing this would be problematic, as there could be code that depends on
getting back the numerical value.
</p>
</div>
</div>
<div id="outline-container-sec-1-4" class="outline-3">
<h3 id="sec-1-4"><code>find_or_initialize_by</code>, oh my!!!</h3>
<div class="outline-text-3" id="text-1-4">
<p>
Let’s suppose we have this persisted in the database:
</p>
<pre class="example">
Conversation {
:id => 18,
:user => 25
:status => "archived" (1 in database)
}
</pre>
<p>
And then we do a <code>find_or_initialize_by</code>:
</p>
<pre class="example">
[47] (pry) main: 0> conversation = Conversation.find_or_initialize_by(user: 25, status: "archived")
Conversation Load (4.6ms) SELECT "conversations".* FROM "conversations"
WHERE "conversations"."user_id" = 25
AND "conversations"."status" = 0 LIMIT 1
#<Conversation:> {
:id => nil,
:user_id => 25,
:status => "archived"
}
</pre>
<p>
We got <code>nil</code> for <code>:id</code>, meaning that we’re creating a new record. Wouldn’t you
expect to find the existing record? Well, maybe not given the way that
<code>ActiveRecord.where</code> works, per the above discussion.
</p>
<p>
Next, the status on the new record is created with “archived”, which is value 1.
Hmmm….If you look closely above, the query uses
</p>
<pre class="example">
AND "conversations"."status" = 0
</pre>
<p>
Let’s look at another example:
</p>
<pre class="example">
Conversation {
:id => 19,
:user => 26
:status => "active" (0 in database)
}
</pre>
<p>
And then we do a <code>find_or_initialize_by</code>:
</p>
<pre class="example">
[47] (pry) main: 0> conversation = Conversation.find_or_initialize_by(user: 26, status: "active")
Conversation Load (4.6ms) SELECT "conversations".* FROM "conversations"
WHERE "conversations"."user_id" = 26
AND "conversations"."status" = 0 LIMIT 1
#<Conversation:> {
:id => 19,
:user_id => 26,
:status => "active"
}
</pre>
<p>
Wow! Is this a source of subtle bugs and some serious yak shaving?
</p>
<p>
Note, the above applies equally to <code>ActiveRecord.find_or_create_by</code>.
</p>
<p>
It turns out that the Rails methods that allow creation of a record via a Hash
of attributes will convert the enum strings to the proper integer values, but
this is not case when querying!
</p>
</div>
</div>
<div id="outline-container-sec-1-5" class="outline-3">
<h3 id="sec-1-5">Rails Default Accessors For Setting Attributes</h3>
<div class="outline-text-3" id="text-1-5">
<p>
You may find it useful to know which Rails methods call the “Default Accessor”
versus just going to the database directly. That makes all the difference in
terms of whether or not you can/should use the string values for enums.
</p>
<p>
The key thing is that that “Uses Default Accessor” means that <b>string enums get converted to the correct database integer values.</b>
</p>
<table border="2" cellspacing="0" cellpadding="6" rules="groups" frame="hsides">
<colgroup>
<col class="left" />
<col class="left" />
</colgroup>
<thead>
<tr>
<th scope="col" class="left">Method</th>
<th scope="col" class="left">Uses Default Accessor (converts string enums to integers!)</th>
</tr>
</thead>
<tbody>
<tr>
<td class="left"><code>attribute=</code></td>
<td class="left">Yes</td>
</tr>
<tr>
<td class="left"><code>write_attribute</code></td>
<td class="left">No</td>
</tr>
<tr>
<td class="left"><code>update_attribute</code></td>
<td class="left">Yes</td>
</tr>
<tr>
<td class="left"><code>attributes=</code></td>
<td class="left">Yes</td>
</tr>
<tr>
<td class="left"><code>update</code></td>
<td class="left">Yes</td>
</tr>
<tr>
<td class="left"><code>update_column</code></td>
<td class="left">No</td>
</tr>
<tr>
<td class="left"><code>update_columns</code></td>
<td class="left">No</td>
</tr>
<tr>
<td class="left"><code>Conversation::update</code></td>
<td class="left">Yes</td>
</tr>
<tr>
<td class="left"><code>Conversation::update_all</code></td>
<td class="left">No</td>
</tr>
</tbody>
</table>
<p>
For more information on this topic, see
</p>
<ol class="org-ol">
<li><a href="http://www.davidverhasselt.com/set-attributes-in-activerecord/">Different Ways to Set Attributes in ActiveRecord</a> by <a href="https://twitter.com/DavidVerhasselt">@DavidVerhasselt</a>.
</li>
<li><a href="http://api.rubyonrails.org/classes/ActiveRecord/Base.html">Official API of ActiveRecord::Base</a>
</li>
<li><a href="http://api.rubyonrails.org/files/activerecord/README_rdoc.html">Official Readme of Active Record – Object-relational mapping put on rails</a>.
</li>
</ol>
<p>
While these don’t mention Rails enums, it’s <b>critical</b> to understand that enums
create default accessors that do the mapping to and from Strings.
</p>
<p>
So when you call these methods, the <b>default accessors</b> are used:
</p>
<figure class='code'><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
</pre></td><td class='code'><pre><code class='ruby'><span class='line'><span class="n">conversation</span><span class="o">.</span><span class="n">status</span> <span class="o">=</span> <span class="s2">"archived"</span>
</span><span class='line'><span class="n">conversation</span><span class="o">.</span><span class="n">status</span> <span class="o">=</span> <span class="mi">1</span>
</span><span class='line'><span class="nb">puts</span> <span class="n">conversation</span><span class="o">.</span><span class="n">status</span> <span class="c1"># prints "archived"</span>
</span></code></pre></td></tr></table></div></figure>
<p>
So keep in mind when those default accessors are used per the above table.
</p>
</div>
</div>
<div id="outline-container-sec-1-6" class="outline-3">
<h3 id="sec-1-6">Deep Dive: Enum Source</h3>
<div class="outline-text-3" id="text-1-6">
<p>
If you look at the Rails <a href="https://github.com/rails/rails/blob/877ea784e4cd0d539bdfbd15839ae3d28169b156/activerecord/lib/active_record/enum.rb#L82">source code for ActiveRecord::Enum</a>, you can see this at
line 91, for the setter of the enum (I added some comments):
</p>
<figure class='code'><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
<span class='line-number'>7</span>
<span class='line-number'>8</span>
<span class='line-number'>9</span>
<span class='line-number'>10</span>
<span class='line-number'>11</span>
<span class='line-number'>12</span>
<span class='line-number'>13</span>
</pre></td><td class='code'><pre><code class='ruby'><span class='line'><span class="n">_enum_methods_module</span><span class="o">.</span><span class="n">module_eval</span> <span class="k">do</span>
</span><span class='line'> <span class="c1"># def status=(value) self[:status] = statuses[value] end</span>
</span><span class='line'> <span class="n">define_method</span><span class="p">(</span><span class="s2">"</span><span class="si">#{</span><span class="nb">name</span><span class="si">}</span><span class="s2">="</span><span class="p">)</span> <span class="p">{</span> <span class="o">|</span><span class="n">value</span><span class="o">|</span>
</span><span class='line'> <span class="k">if</span> <span class="n">enum_values</span><span class="o">.</span><span class="n">has_key?</span><span class="p">(</span><span class="n">value</span><span class="p">)</span> <span class="o">||</span> <span class="n">value</span><span class="o">.</span><span class="n">blank?</span>
</span><span class='line'> <span class="c1"># set the db value to the integer value for the enum</span>
</span><span class='line'> <span class="nb">self</span><span class="o">[</span><span class="nb">name</span><span class="o">]</span> <span class="o">=</span> <span class="n">enum_values</span><span class="o">[</span><span class="n">value</span><span class="o">]</span>
</span><span class='line'> <span class="k">elsif</span> <span class="n">enum_values</span><span class="o">.</span><span class="n">has_value?</span><span class="p">(</span><span class="n">value</span><span class="p">)</span> <span class="c1"># values contains the integer</span>
</span><span class='line'> <span class="nb">self</span><span class="o">[</span><span class="nb">name</span><span class="o">]</span> <span class="o">=</span> <span class="n">value</span>
</span><span class='line'> <span class="k">else</span>
</span><span class='line'> <span class="c1"># enum_values did not have the key or value passed</span>
</span><span class='line'> <span class="k">raise</span> <span class="no">ArgumentError</span><span class="p">,</span> <span class="s2">"'</span><span class="si">#{</span><span class="n">value</span><span class="si">}</span><span class="s2">' is not a valid </span><span class="si">#{</span><span class="nb">name</span><span class="si">}</span><span class="s2">"</span>
</span><span class='line'> <span class="k">end</span>
</span><span class='line'> <span class="p">}</span>
</span></code></pre></td></tr></table></div></figure>
<p>
From this definition, you see that both of these work:
</p>
<figure class='code'><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
</pre></td><td class='code'><pre><code class='ruby'><span class='line'><span class="n">conversation</span><span class="o">.</span><span class="n">status</span> <span class="o">=</span> <span class="s2">"active"</span>
</span><span class='line'><span class="n">conversation</span><span class="o">.</span><span class="n">status</span> <span class="o">=</span> <span class="mi">0</span>
</span></code></pre></td></tr></table></div></figure>
<p>
Here’s the definition for the getter, which I’ve edited a bit for illustrative
purposes:
</p>
<figure class='code'><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
</pre></td><td class='code'><pre><code class='ruby'><span class='line'><span class="c1"># def status() statuses.key self[:status] end</span>
</span><span class='line'><span class="n">define_method</span><span class="p">(</span><span class="nb">name</span><span class="p">)</span> <span class="k">do</span>
</span><span class='line'> <span class="n">db_value</span> <span class="o">=</span> <span class="nb">self</span><span class="o">[</span><span class="nb">name</span><span class="o">]</span> <span class="c1"># such as 0 or 1</span>
</span><span class='line'> <span class="n">enum_values</span><span class="o">.</span><span class="n">key</span><span class="p">(</span><span class="n">db_value</span><span class="p">)</span> <span class="c1"># the key value, like "archived" for db_value 1</span>
</span><span class='line'><span class="k">end</span>
</span></code></pre></td></tr></table></div></figure>
</div>
</div>
<div id="outline-container-sec-1-7" class="outline-3">
<h3 id="sec-1-7">Recommendations to the Rails Core Team</h3>
<div class="outline-text-3" id="text-1-7">
<p>
In response to this issue, I submitted this github issue:
<a href="https://github.com/rails/rails/issues/17226">Rails where query should see value is an enum and convert a string #17226</a>
</p>
<ol class="org-ol">
<li>@Bounga and @rafaelfranca on Github suggest that we can’t automatically
convert enum string values in queries. I think that is true for converting
cases of a <code>?</code> or a named param, but I suspect that a quick map lookup to see
that the attribute is an enum, and a string is passed, and then converting
the string value to an integer is the right thing to do for 2 reasons:
<ol class="org-ol">
<li>This is the sort of “magic” that I expect from Rails.
</li>
<li>Existing methods <code>find_or_initialize_by</code> and <code>find_or_create_by</code> will
result in obscure bugs when string params are passed for enums.
</li>
</ol>
<p>
However, it’s worth considering if all default accessor methods (setters)
should be consistently be called for purposes of passing values in a map to
such methods. I would venture that Rails enums are some Rails provided magic,
and thus they should have a special case. If this shouldn’t go into Rails,
then possibly a gem extension could provide a method like
<code>Model.where_with_enum</code> which would convert a String into the proper
numerical value for the enum. I’m not a huge fan of the generated Model
scopes for enums, as <b>I like to see what database field is being queried
against.</b>
</p>
</li>
<li>Aside from putting automatic conversion of the enum hash attributes, I
recommend we change the automatic conversion of Strings to integers to use
the stricter <code>Integer(some_string)</code> rather than <code>some_string.to_i</code>. The
difference is considerable, <code>String#to_i</code> is extremely permissive. Try it in
a console. With the <code>to_i</code> method, any number characters at the beginning of
the String are converted to an Integer. If the first character is not a
number, <b>0 is returned</b>, which is almost certainly a default enum value.
Thus, this simple change would make it <b>extremely</b> clear when an enum string
is improperly used. I would guess that this would make some existing code
crash, but in all circumstances for a valid reason. As to whether this change
should be done for all integer attributes is a different discussion, as that
could have backwards compatibility ramifications. This change would require changing the tests in <a href="https://github.com/rails/rails/blob/master/activerecord/test/cases/types_test.rb">ActiveRecord::ConnectionAdapters::TypesTest</a>. For example, this test:
<figure class='code'><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
</pre></td><td class='code'><pre><code class='ruby'><span class='line'><span class="n">assert_equal</span> <span class="mi">0</span><span class="p">,</span> <span class="n">type</span><span class="o">.</span><span class="n">type_cast_from_user</span><span class="p">(</span><span class="s1">'bad'</span><span class="p">)</span>
</span></code></pre></td></tr></table></div></figure>
<p>
would change to throw an exception, unless the cases are restricted to using
Integer.new() for enums. It is inconsistent that some type conversions throw
exceptions, such as converting a symbol to an integer. Whether or not they
should is much larger issue. In the case of enums, <b>I definitely believe that proper enum string value should not silently convert to zero every time.</b>
</p>
</li>
</ol>
</div>
</div>
</div>
<div id="outline-container-sec-2" class="outline-2">
<h2 id="sec-2">Conclusion</h2>
<div class="outline-text-2" id="text-2">
<p>
I hope this article has convinced you that it’s worth understanding Ruby as much
as it is to understand Rails. Additionally, the new Enum feature in 4.1 requires
some careful attention!
</p>
<p>
Thanks to Hack Hands for supporting the development of this content. You can
find <a href="https://hackhands.com/ruby-on-enums-queries-and-rails-4-1/">a copy of this article in their blog</a>.
</p>
</div>
</div>
<div id="discourse-comments"></div>
<script type="text/javascript">
var discourseUrl = "http://forum.railsonmaui.com/",
discourseEmbedUrl = "http://www.railsonmaui.com//blog/2014/10/22/enums-and-queries-in-rails-4-dot-1/";
(function() {
var d = document.createElement('script'); d.type = 'text/javascript'; d.async = true;
d.src = discourseUrl + 'javascripts/embed.js';
(document.getElementsByTagName('head')[0] || document.getElementsByTagName('body')[0]).appendChild(d);
})();
</script>
</div>
</article>
<article>
<header>
<h1 class="entry-title"><a href="/blog/2014/10/08/adding-a-js-library-when-using-webpack/">Adding a JS LIbrary to a Ruby on Rails Project When Using Webpack</a></h1>
<p class="meta">
<time class='entry-date' datetime='2014-10-08T11:49:26-10:00'><span class='date'><span class='date-month'>Oct</span> <span class='date-day'>8</span><span class='date-suffix'>th</span>, <span class='date-year'>2014</span></span> <span class='time'>11:49 am</span></time>
</p>
</header>
<div class="entry-content"><p>
What’s it like to add a JavaScript library when Webpack is integrated into your
Ruby on Rails environment, per my article: <a href="http://www.railsonmaui.com/blog/2014/10/02/integrating-webpack-and-the-es6-transpiler-into-an-existing-rails-project/">Fast Rich Client Rails Development With Webpack and the ES6 Transpiler</a>?
</p>
<p>
It’s super easy! But what if you want some of your the legacy JavaScript or
CoffeeScript code in your Rails app to access the Webpack added library?
</p>
<p>
Here’s a real world example. Suppose you want your JavaScript code to round
numbers to decimal places. <a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Math/round">Math.round()</a> only rounds decimal numbers to the
nearest integer. A code sample on that page is provided to show you how round
numbers off to some number of decimal places.
</p>
<p>
A quick Google for JavaScript libraries finds <a href="https://www.npmjs.org/package/compute-roundn">npm package compute-roundn</a>. A look
at the <a href="https://github.com/compute-io/roundn">github repository for compute-io/roundn</a> reveals clean code and it has
some tests.
</p>
<p>
So should you copy some cribbed JavaScript code example or maybe copy-paste the
source of some code into your <code>/vendor/assets/javascripts</code> directory? What’s the
disadvantage of doing this?
</p>
<ol class="org-ol">
<li>It becomes your problem to maintain this code. Imagine if you had to maintain
all the code behind the Ruby Gems in your Rails project?
</li>
<li>If you copy the code, are you going to create some tests?
</li>
<li>What if this code depends on other JavaScript libraries? Or what if you later
want a library that depends on this library?
</li>
</ol>
<p>
There is a better way, by using npm packages. And yes, there are alternatives
for Rails using Bower, but many more packages are available via npm than Bower.
There is also the <a href="https://github.com/browserify-rails/browserify-rails">browserify-rails</a> gem, and the steps below mostly apply to this
gem.
</p>
<p>
Assuming that you’ve got your Rails codebase set up per my article <a href="http://www.railsonmaui.com/blog/2014/10/02/integrating-webpack-and-the-es6-transpiler-into-an-existing-rails-project/">article on Webpack in Rails</a>,
as shown in this sample Github repo: <a href="https://github.com/justin808/react-webpack-rails-tutorial">justin808/react-webpack-rails-tutorial</a>,
you’ll need to follow these steps.
</p>
<ol class="org-ol">
<li>Google for the <b>npm package</b> that you wish to use. I typically Google “npm
<some keywords>”. Then take a look at the code and see how popular it is.
You’ll want to more carefully examine the code of less popular node packages,
as with less popularity, there’s a great likelihood of unreported and unfixed
bugs.
</li>
<li>In my case, I found the package for “compute-roundn”, so I ran this command:
<figure class='code'><figcaption><span></span></figcaption><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
</pre></td><td class='code'><pre><code class='bash'><span class='line'>npm install compute-roundn <span class="p">&</span><span class="c">#x2013;save</span>
</span></code></pre></td></tr></table></div></figure>
That adds this entry to your <a href="https://github.com/justin808/react-webpack-rails-tutorial/blob/master/package.json">/package.json</a>
<figure class='code'><figcaption><span></span></figcaption><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
</pre></td><td class='code'><pre><code class='json'><span class='line'><span class="p">{</span> <span class="nt">"dependencies"</span><span class="p">:</span> <span class="p">{</span>
</span><span class='line'> <span class="nt">"compute-roundn"</span><span class="p">:</span> <span class="s2">"^1.0.0"</span><span class="p">,</span>
</span></code></pre></td></tr></table></div></figure>
</li>
<li>Run the command to create <code>/npm-shrinkwrap.json</code>
<figure class='code'><figcaption><span></span></figcaption><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
</pre></td><td class='code'><pre><code class='bash'><span class='line'>npm-shrinkwrap
</span></code></pre></td></tr></table></div></figure>
It’s <b>critical that you don’t forget</b> to update this file, because if you
forget, your Heroku build will fail, as the Node buildpack will not install
your newly added package!
</li>
<li>If you needed this code for your module based Webpack code, then you just
need to add in the require line at the top of relevant JavaScript file, like
this (as show in the <a href="https://www.npmjs.org/package/compute-roundn">npm readme for roundn</a>):
<figure class='code'><figcaption><span></span></figcaption><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
</pre></td><td class='code'><pre><code class='javascript'><span class='line'><span class="kd">var</span> <span class="nx">roundn</span> <span class="o">=</span> <span class="nx">require</span><span class="p">(</span> <span class="s1">'compute-roundn'</span> <span class="p">);</span>
</span></code></pre></td></tr></table></div></figure>
Yipee. That’s it!
</li>
<li>If you need this library for your existing Rails JavaScript or CoffeeScript
code, then you’ll need to globally export the library. Assuming that the
module code based code is not needing this library as well, then you’ll want
to edit your file called <a href="https://github.com/justin808/react-webpack-rails-tutorial/blob/master/webpack/scripts/rails_only.jsx">/webpack/scripts/rails_only.jsx</a> and add this
line:
<figure class='code'><figcaption><span></span></figcaption><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
</pre></td><td class='code'><pre><code class='javascript'><span class='line'><span class="nb">window</span><span class="p">.</span><span class="nx">roundn</span> <span class="o">=</span> <span class="nx">require</span><span class="p">(</span><span class="s2">"compute-roundn"</span><span class="p">);</span>
</span></code></pre></td></tr></table></div></figure>
That file gets loaded by <a href="https://github.com/justin808/react-webpack-rails-tutorial/blob/master/webpack/webpack.rails.config.js">webpack.rails.config.js</a> and not by running the
Webpack Dev server.
</li>
<li>There is an alternative approach of modifying the webpack config file, if you
were also referencing this library for some other Webpack bundled code. This,
you would change <a href="https://github.com/justin808/react-webpack-rails-tutorial/blob/master/webpack/webpack.rails.config.js">webpack.rails.config.js</a> file with these lines:
<figure class='code'><figcaption><span>exports.module.loaders = [{ test:</span></figcaption><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
</pre></td><td class='code'><pre><code class='javascript'><span class='line'><span class="nx">require</span><span class="p">.</span><span class="nx">resolve</span><span class="p">(</span><span class="s2">"compute-roundn"</span><span class="p">),</span> <span class="nx">loader</span><span class="o">:</span> <span class="s2">"expose?roundn"</span> <span class="p">}];</span>
</span></code></pre></td></tr></table></div></figure>
Note, that doesn’t work unless you have other code loaded by Webpack that
“requires” this package.
</li>
<li>When you deploy to Heroku, you see this:
<pre class="example">
-----> Installing dependencies
[email protected] node_modules/compute-roundn
</pre>
<p>
If you have problems with your Heroku deploy failing to install dependencies,
check out this article in my forum: <a href="http://forum.railsonmaui.com/t/notes-on-deploying-to-heroku-with-gsl-and-node/89">Notes on Deploying to Heroku with GSL and Node</a>.
</p>
</li>
</ol>
<p>
You maybe wondering, “why not just use the <a href="https://github.com/browserify-rails/browserify-rails">browserify-rails</a> gem, which is
slightly simpler in terms of setup. A good reason would be that you want to use
JSX and ES6 transpilers with your JavaScript code. That was my reason.
</p>
<p>
That’s it! I hope you agree is way better than copy-pasting dependencies.
</p>
<div id="discourse-comments"></div>
<script type="text/javascript">
var discourseUrl = "http://forum.railsonmaui.com/",
discourseEmbedUrl = "http://www.railsonmaui.com//blog/2014/10/08/adding-a-js-library-when-using-webpack/";
(function() {
var d = document.createElement('script'); d.type = 'text/javascript'; d.async = true;
d.src = discourseUrl + 'javascripts/embed.js';
(document.getElementsByTagName('head')[0] || document.getElementsByTagName('body')[0]).appendChild(d);
})();