/
read-active-record-columns-directly-from-the-class.html
112 lines (95 loc) · 6.64 KB
/
read-active-record-columns-directly-from-the-class.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
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<meta http-equiv="X-UA-Compatible" content="chrome=1" />
<meta name="viewport" content="width=device-width, minimum-scale=1.0" />
<link rel="stylesheet" href="/css/style-c5940180f1eee87aee88f035a95023ac.css" type="text/css" />
<link rel="alternate" type="application/atom+xml" href="http://tomafro.net/atom.xml" />
<link rel="canonical" href="http://tomafro.net/2009/05/read-active-record-columns-directly-from-the-class"/>
<script type="text/javascript" src="http://use.typekit.com/brv6igt.js"></script>
<script type="text/javascript">try{Typekit.load();}catch(e){}</script>
<title>Read ActiveRecord columns directly from the class · tomafro.net</title>
<script type="text/javascript">
var _gaq = _gaq || [];
_gaq.push(['_setAccount', 'UA-1103395-2']);
_gaq.push(['_trackPageview']);
(function() {
var ga = document.createElement('script');
ga.src = ('https:' == document.location.protocol ? 'https://ssl' :
'http://www') + '.google-analytics.com/ga.js';
ga.setAttribute('async', 'true');
document.documentElement.firstChild.appendChild(ga);
})();
</script>
<!--[if lt IE 9]>
<script src="//html5shiv.googlecode.com/svn/trunk/html5.js"></script>
<![endif]-->
</head>
<body>
<nav>
<ul>
<li><a href='/'>tomafro.net</a><span class='byline'>, a blog by Tom Ward</span></li>
<li><a href='/about'>about</a></li>
<li><a href='https://github.com/tomafro'>github</a></li>
<li><a href='https://twitter.com/tomafro'>twitter</a></li>
</ul>
</nav>
<article>
<header>
<h1><a href="/2009/05/read-active-record-columns-directly-from-the-class">Read ActiveRecord columns directly from the class</a></h1>
</header>
<div class="content">
<p>Sometimes you want to read just a single column from a collection of records, without the overhead of instantiating each and every one. You could just execute raw SQL, but it's a shame to do away with the nice type conversion <code>ActiveRecord</code> provides. It'd also be a pity to get rid of find scoping, amongst other goodness.</p>
<p>Enter <code>Tomafro::ColumnReader</code>:</p>
<div class="highlight"><pre><span class="k">module</span> <span class="nn">Tomafro::ColumnReader</span>
<span class="k">def</span> <span class="nf">column_reader</span><span class="p">(</span><span class="n">column_name</span><span class="p">,</span> <span class="n">options</span> <span class="o">=</span> <span class="p">{})</span>
<span class="nb">name</span> <span class="o">=</span> <span class="n">options</span><span class="o">.</span><span class="n">delete</span><span class="p">(</span><span class="ss">:as</span><span class="p">)</span> <span class="o">||</span> <span class="n">column_name</span><span class="o">.</span><span class="n">to_s</span><span class="o">.</span><span class="n">pluralize</span>
<span class="n">column</span> <span class="o">=</span> <span class="n">columns_hash</span><span class="o">[</span><span class="n">column_name</span><span class="o">.</span><span class="n">to_s</span><span class="o">]</span>
<span class="nb">self</span><span class="o">.</span><span class="n">module_eval</span> <span class="sx">%{</span>
<span class="sx"> def self.</span><span class="si">#{</span><span class="nb">name</span><span class="si">}</span><span class="sx">(options = {})</span>
<span class="sx"> merged = options.merge(:select => '</span><span class="si">#{</span><span class="n">column_name</span><span class="si">}</span><span class="sx">')</span>
<span class="sx"> connection.select_all(construct_finder_sql(merged)).collect do |value| </span>
<span class="sx"> v = value.values.first</span>
<span class="sx"> </span><span class="si">#{</span><span class="n">column</span><span class="o">.</span><span class="n">type_cast_code</span><span class="p">(</span><span class="s1">'v'</span><span class="p">)</span><span class="si">}</span><span class="sx"></span>
<span class="sx"> end</span>
<span class="sx"> end</span>
<span class="sx"> }</span>
<span class="k">end</span>
<span class="k">end</span>
</pre>
</div>
<p>Once you've extended <code>ActiveRecord::Base</code> with it, usage is simple. In your models, declare which columns you want access to:</p>
<div class="highlight"><pre><span class="no">ActiveRecord</span><span class="o">::</span><span class="no">Base</span><span class="o">.</span><span class="n">extend</span> <span class="no">Tomafro</span><span class="o">::</span><span class="no">ColumnReader</span>
<span class="k">class</span> <span class="nc">Animal</span> <span class="o"><</span> <span class="no">ActiveRecord</span><span class="o">::</span><span class="no">Base</span>
<span class="n">column_reader</span> <span class="s1">'id'</span>
<span class="n">column_reader</span> <span class="s1">'name'</span>
<span class="n">named_scope</span> <span class="ss">:dangerous</span><span class="p">,</span> <span class="ss">:conditions</span> <span class="o">=></span> <span class="p">{</span><span class="ss">:carnivorous</span> <span class="o">=></span> <span class="kp">true</span><span class="p">}</span>
<span class="k">end</span>
</pre>
</div>
<p>Once you've done this, you can access values directly from the class, respecting scope, limits and other finder options.</p>
<div class="highlight"><pre><span class="no">Animal</span><span class="o">.</span><span class="n">names</span>
<span class="c1">#=> ['Lion', 'Tiger', 'Zebra', 'Gazelle']</span>
<span class="no">Animal</span><span class="o">.</span><span class="n">names</span> <span class="ss">:limit</span> <span class="o">=></span> <span class="mi">1</span>
<span class="c1">#=> ['Lion'] (Normal finder options supported)</span>
<span class="no">Animal</span><span class="o">.</span><span class="n">dangerous</span><span class="o">.</span><span class="n">names</span>
<span class="c1">#=> ['Lion', 'Tiger'] (Scoping respected)</span>
<span class="no">Animal</span><span class="o">.</span><span class="n">ids</span>
<span class="c1">#=> [1, 2, 3] (Values cast correctly)</span>
</pre>
</div>
</div>
<footer>
<span class='author'><a rel='author' href='http://tomafro.net'>Tom Ward</a></span>
<span class='date'><a href="/2009/05">29th May 2009</a></span>
<ul>
<li><a href="/tags/ruby" rel="tag">ruby</a></li>
<li><a href="/tags/rails" rel="tag">rails</a></li>
<li><a href="/tags/active-record" rel="tag">active-record</a></li>
<li><a href="/tags/column-reader" rel="tag">column-reader</a></li>
</ul>
</footer>
</article>
</body>
</html>