Jekyll2018-10-24T16:35:08+00:00https://schwad.github.io/SchwadI am a Full Stack Ruby on Rails Software Engineer for OceansHQ in Torpoint, England.
Talking about my first Rails pull request on The Ruby on Rails Podcast2018-10-16T14:34:09+00:002018-10-16T14:34:09+00:00https://schwad.github.io/ruby/rails/community/2018/10/16/talking-about-my-first-rails-core-pull-request-on-the-ruby-on-rails-podcast<p style="text-align:center"><img src="https://i.imgur.com/XIOBAIg.png" alt="Favorite" /></p>
<p>I have been listening to a slew of Ruby and Rails podcasts for years <a href="https://schwad.github.io/favorite_resources/">(you can see some of my favorites here)</a>.</p>
<p>One that I absolutely love is <a href="http://5by5.tv/rubyonrails">The Ruby on Rails Podcast</a> hosted by <a href="https://twitter.com/BrittJMartin">Brittany Martin</a>. At the time of writing it’s closing in on its 250th episode and will be <a href="http://5by5.tv/rubyonrails/page/25"><em>celebrating its 10th anniversary in a few months</em></a>. Wow.</p>
<p>Needless to say I was absolutely honored when I was invited to speak and share my story a few weeks ago; from dipping my toes into very small bits of open source to getting a meaningful Rails PR accepted by DHH himself. <a href="http://5by5.tv/rubyonrails/245">Check it out! And subscribe if you haven’t!</a></p>
<p style="text-align:center"><a href="http://5by5.tv/rubyonrails/245"><img src="https://i.imgur.com/GPCKTrI.png" alt="Ruby Talk" /></a></p>Speaking on Ruby and Chronic Pain Management in Sheffield2018-10-16T14:34:09+00:002018-10-16T14:34:09+00:00https://schwad.github.io/ruby/rails/community/2018/10/16/speaking-on-ruby-and-chronic-pain-management-at-sheffield-ruby<p style="text-align:center"><a href="https://www.youtube.com/watch?v=ZtBckwQaEBA"><img src="https://i.imgur.com/32Q56dM.png" alt="Ruby Talk" /></a></p>
<p>I was recently invited to <a href="https://shrug.org/meetings/shrug-103/">Sheffield Ruby User Group</a> to share the story of MaraBot, <a href="https://github.com/schwad/mara">a very personal project</a> to help use machine learning and weather shifts to regain control over managing chronic pain.</p>
<p>Around the time of giving this talk I had started the full-application-rewrite. This revisit shifts focus to multiple open users and using Telegram instead of Twilio for interactions (and to enable location sharing). It will also automate nightly ‘forecast tests’ to improve over the ‘manual accuracy tests’ I had been running myself before.</p>
<p>I am happy to report the rewrite has entered alpha-testing and will hopefully be green-lit for beta-testing in the next few weeks. I am very much looking forward to writing a more in depth article (and speaking) on the results of further iterations.</p>
<p>If this topic interests you or if you want to help contribute pain reading data - <a href="https://twitter.com/schwad4hd14">feel free to reach out</a></p>How I got my first pull request merged on Rails-core2018-09-06T14:34:09+00:002018-09-06T14:34:09+00:00https://schwad.github.io/ruby/rails/community/2018/09/06/how-i-got-my-first-pull-request-merged-on-rails-core<p style="text-align:center"><img src="https://i.imgur.com/XIOBAIg.png" alt="Favorite" /></p>
<p><a href="https://github.com/rails/rails/pull/33523">DHH recently reviewed and merged my first ever pull request to Rails core</a>. Short of getting my first Ruby job years ago, this is my most proud Ruby-achievement to date.</p>
<p>Open source contributions are terrifying to many - even me.</p>
<p>I want to tell you how I got here. This post will be equal parts personal experiences and concrete steps to meaningfully level up your open-source participation <strong>while still being a hard-working developer at your day job</strong>.</p>
<h2 id="why-contribute">Why contribute?</h2>
<p>It is important to approach contributions with <strong>healthy</strong> motivations. This will help the process come more naturally and enjoyably.</p>
<p>You should contribute in order to:</p>
<ul>
<li>Give back to the community that you rely on</li>
<li>Interact with other developers who are just as passionate about these projects as you</li>
<li>Provide your voice, perspective and feedback to diversify the OSS community</li>
<li>Level up your understanding of core tooling</li>
</ul>
<p>You should not contribute in order to:</p>
<ul>
<li>Be seen by potential employers</li>
<li>Make your github commit chart dark green</li>
</ul>
<p>These are all nice-to-haves that may actually occur, but are unlikely to be sustainable motivations for you as a developer.</p>
<h2 id="okay-but-where-do-i-start-">Okay, but where do I start? 🤔</h2>
<p>To get started, do not troll around on github reading endless lists of pull requests and issues. You need a constant guided feed of things to review, and the perfect tool for that (<a href="https://github.com/schneems">very kindly created by Schneems</a>) is CodeTriage.</p>
<p style="text-align:center"><img src="https://i.imgur.com/DAbjF4H.png" alt="Favorite" /></p>
<p>Go to <a href="https://www.codetriage.com">codetriage.com</a> and sign up. Right now. Go ahead, open a new tab and I will still be here when you come back. If you take absolutely nothing from this piece except for joining codetriage, I will feel justified.</p>
<p>CodeTriage is a tool that allows you to ‘subscribe’ to github repositories that you may be interested in contributing to. Then, once a week, it feeds you a sample of pull requests and issues from those repositories that have not been recently reviewed (all via email). You can configure how often you get these emails and how many issues are included with them.</p>
<p>Do this, and just get in the habit of reading what comes in at first. Then, jump in. I recommend the following contributions at least at first, and if you never graduate beyond this you will still be a massive OSS help:</p>
<h3 id="be-the-human-advocate-of-the-issue-or-pull-request-">Be the human advocate of the issue or pull request 🙋</h3>
<p style="text-align:center"><img src="https://i.imgur.com/77Zc2i0.png" alt="Favorite" /></p>
<p>This is 80-85% of what I do (and I do not do much, but more on that later). You will see issues and PR’s that have stagnated for months or years. You are completely allowed to pop your head around the corner and ask:</p>
<p><code class="highlighter-rouge">"@user, do you feel that your question has been fully answered, so we can close this?"</code> or <code class="highlighter-rouge">"Hello @user_2! Any chance you've had an opportunity to get that commit together?"</code>.</p>
<p>People have tried to do this with bots, but there is nothing like the urgency of a real, empathetic, caring human behind the ping.</p>
<p>This is 100% of how I use code triage. Even if you ignore your emails and only look at 4-6 issues for a half hour a month, you are giving back in a big way.</p>
<h3 id="drive-your-gemsdependencies-forward-️">Drive your gems/dependencies forward ➡️</h3>
<p style="text-align:center"><img src="https://i.imgur.com/x8s8JVG.png" alt="Favorite" /></p>
<p>Your applications have dependencies. There’s no way around it.</p>
<p>Those who have taken larger applications through major Rails upgrades know all-too-well the pain of gem version conflicts holding the upgrade back. The next time this happens with you, instead of forking and bumping the gem or filing an issue with the maintainers, file a PR updating the <code class="highlighter-rouge">gemspec</code> to support your latest Ruby or Rails version. (<code class="highlighter-rouge">Note: do your due diligence to ensure that the gem still functions with the new bump.</code>)</p>
<p>This habit actually will help you get involved in larger projects: a win for you and the community!</p>
<p>Recently, this approach led myself and a group of developers to actually move forward with <a href="https://schwad.github.io/ruby/rails/community/2018/08/21/new-community-maintained-trix-gem.html">a new <code class="highlighter-rouge">trix</code> gem after the current one lapsed in maintenance</a>.</p>
<p>Also during a Rails 5 major upgrade, I came across a non-Rails-5-complaint and <a href="https://github.com/activerecord-hackery/squeel/pull/428">unmaintained</a> gem. Participating in the discussion helped myself and other developers to move to <a href="https://github.com/rzane/baby_squeel">another maintained gem</a> where I was afforded the chance to help build out the ‘migration’ part of the wiki. I now have more confidence in the future of my dependencies by participating in the community.</p>
<h3 id="flag-up-the-problem-clearly-">Flag up the problem, clearly 🚩</h3>
<p>Occasionally you will come across a genuine problem or issue with open-sourced code that you rely on. Often times we find ‘hacky’ ways around the problem or simply stop using that element of functionality.</p>
<p>Here’s the thing: <strong>if you have struggled with a problem, odds are someone else has too</strong>.</p>
<p>This is the one element you are most likely to do already, but I really want to underline the importance of sharing issues with the community. That leads to the next issue:</p>
<h3 id="file-a-pr-for-what-you-want-solved-">File a PR for what you want solved ✅</h3>
<p style="text-align:center"><img src="https://i.imgur.com/lQola4S.png" alt="Favorite" /></p>
<p>When you encounter an issue - if you possibly can - try to file a PR over an issue. This honors maintainers by showing your personal investment in the issue. It also feeds, big time, the above-mentioned benefit of getting you familiar with the core technologies you rely on. Just remember that <strong>closures are OKAY.</strong></p>
<p>When I used <a href="https://edgeguides.rubyonrails.org/active_storage_overview.html">active storage</a> for the first time, the process was as slick as you could imagine. A handful of commands, rake tasks, minimal code required- and I was up and rolling. <strong>EXCEPT IN ONE PLACE</strong></p>
<p>ActiveStorage only works with activerecord objects using integer primary keys. It does not support other types like UUID out of the box. Further, there was no clear ‘way’ to implement this. I ended up having to go through a <a href="https://www.wrburgess.com/posts/2018-02-03-1.html">step-by-step guide</a> built out by another developer. That did not feel right.</p>
<p>Instead of simply firing up an issue complaining about this, I <a href="https://github.com/rails/rails/pull/32466">filed my own Rails pull request to have a crack at implementing what I wanted.</a>. It was a difficult slog. I worked through an area of Rails-core that I was not familiar with.</p>
<p>After a back-and-forth and several commits, I actually ended up closing the PR. The need was not strong enough and my skills in that area were not sufficient. Like above, closures are okay and healthy. Even if your code does not make it to prime-time the discussion is preserved there as its own documentation.</p>
<h3 id="️-it-is-okay-to-flakily-make-small-contributions-️">⚠️ It is okay to flakily make small contributions ⚠️</h3>
<p>Only a small segment of our community will be able to dedicate full-time or even 5-10H/week to open source participation and contributions. Those of us working full time will often feel ‘guilt’ about neglecting our OSS-time. Don’t. If you end up looking at CodeTriage twice a year for half an hour, filing half a dozen issues a year, and filing one meaningful PR every 18 months, you are still lapping the developer who is doing nothing.</p>
<p style="text-align:center"><img src="https://i.imgur.com/B0JHLJz.png" alt="Favorite" /></p>
<h3 id="take-ownership-">Take ownership 🔥</h3>
<p>All of the above revolves around one idea - ‘take ownership’. You are a part of the community of the code you use. Participate. Speak up. Be heard. Your advancement will happen naturally.</p>
<p>Rails 5.1 <a href="https://m.patrikonrails.com/rails-5-1s-form-with-vs-old-form-helpers-3a5f72a8c78a">introduced form_with, effectively ‘soft-replacing’ form_tag and form_for</a>. I thoroughly enjoyed jumping on this approach with all new forms on upgraded apps. I used the <a href="https://api.rubyonrails.org/classes/ActionView/Helpers/FormHelper.html#method-i-form_with">core docs whenever I had a question</a>. One day I found my way on <a href="https://edgeguides.rubyonrails.org/form_helpers.html">Rails Guides</a> with a question about <code class="highlighter-rouge">form_with</code>, and noticed that it was not mentioned anywhere in the form helper guide. In its place were still mentions solely of <code class="highlighter-rouge">form_for</code> and <code class="highlighter-rouge">form_tag</code>. That did not seem quite right. <strong>(NOTE: The code for Rails Guides is a part of Rails-core)</strong></p>
<p>I found my way to the original <code class="highlighter-rouge">form_with</code> issue and <a href="https://github.com/rails/rails/issues/25197#issuecomment-408386800">asked about this, offering to help in any way I could</a>. <a href="https://github.com/rails/rails/issues/25197#issuecomment-408600838">The original author</a> and <a href="https://github.com/rails/rails/issues/25197#issuecomment-408448753">DHH himself</a> agreed with my observation, and told me to ‘take a stab at it’! 😱</p>
<p><strong>No Pressure</strong></p>
<p style="text-align:center"><img src="https://i.imgur.com/s0jWege.png" alt="Favorite" /></p>
<p>I nervously added a discussion about form_with to the guides, and after a code review reworked the whole guide to only mention <code class="highlighter-rouge">form_with</code> with a <code class="highlighter-rouge">form_for/form_tag</code> footnote. <a href="https://github.com/rails/rails/pull/33523">It was ultimately reviewed and merged!</a> I will be doing a further overhaul PR in the new future as well.</p>
<p>At no point was I <strong>trying</strong> to get the ‘Rails Contributor’ feather in my cap. I just wanted to ‘take ownership’ of what mattered to me. So should you.</p>New additions to my favorite Ruby community resources2018-09-04T14:34:09+00:002018-09-04T14:34:09+00:00https://schwad.github.io/ruby/rails/community/2018/09/04/new-additions-to-my-favorite-ruby-community-resources<p style="text-align:center"><img src="https://i.imgur.com/khXOwRk.jpg" alt="Favorite" /></p>
<p>A few months ago I <a href="https://schwad.github.io/ruby/rails/community/resources/2018/05/03/my-favorite-ruby-community-resources.html">wrote about my favorite community resources, which was a really fun exercise.</a> I have since extracted that list into a <a href="https://schwad.github.io/favorite_resources">maintained static page on this site.</a></p>
<p>I built up these resources because I have a joy in discovering new corners of the Ruby community. I have some additions to share. Enjoy and as always, join in with your favorites that I have missed! (some recommended -and discovered- from commenters on the original post!)</p>
<h3 id="gorails---screencast"><a href="https://gorails.com/">GoRails</a> - Screencast</h3>
<p>This is the <em>first</em> resource that I kicked myself for forgetting on the first go around. The creator maintains a consistent stream of high-quality, thoughtful, relevant Rails-based screencasts. I heartily recommend checking it out. As a remote developer sometimes it is valuable to <em>watch</em> someone build something out with a set of new tooling, as I do not always have the advantage to pair with a partner.</p>
<h3 id="the-yak-shave---podcast"><a href="https://yakshave.fm">The Yak Shave</a> - Podcast</h3>
<p><a href="https://www.twitter.com/sgrif">Sean Griffin</a> and <a href="https://www.twitter.com/samphippen">Sam Phippen</a> have joined forces to launch a new highly-anticipated podcast into the Ruby universe. Derek and Sean recently moved on past the bike shed (which is still going with some fantastic new hosts)- so if that was up your alley I recommend subscribing to this.</p>
<h3 id="ruby-on-reddit---community"><a href="https://www.reddit.com/r/ruby/">Ruby on Reddit</a> - Community</h3>
<p>I reckon you know this already, right? If not, go subscribe and throw your upvotes to this nice chunk of our community.</p>
<h3 id="rubysocial---community"><a href="ruby.social">ruby.social</a> - Community</h3>
<p>I only <strong>just</strong> discovered this before writing and it may be the one I am most excited about. There is a new ruby-focused mastodon instance and within a handful of days over 500 rubyists have already joined in. It is an instance-ized social network that operates in a very similar flow to twitter. Since it is full of Rubyists it is obviously incredibly friendly. ☺️</p>
<h3 id="ruby-libhunt-and-ruby-toolbox---library-hunting"><a href="https://ruby.libhunt.com/">Ruby Libhunt</a> AND <a href="https://www.ruby-toolbox.com/">Ruby Toolbox</a> - Library Hunting</h3>
<p>What gems are available for searching in Rails apps? What about geolocation? Which ones are the most used or actively maintained? What’s new and cool in Rubyland for gems? All of these questions and more you can answer at Libhunt and Ruby-Toolbox. This is <em>incredibly</em> useful as a rubyist.</p>
<h3 id="httprubylandnews-and-rubyflow---aggregation"><a href="http://rubyland.news/">http://rubyland.news/</a> AND <a href="www.rubyflow.com">RubyFlow</a> - Aggregation</h3>
<p>RubyFlow is a place where you can share your work in the Ruby community openly, and since it is closely coupled with RubyWeekly oftentimes posts there will end up on the weekly newsletter. So get the breaking news at RubyFlow!</p>
<p>RubyLand has some top-notch daily aggregation. Imagine, essentially, if someone read all the resources I recommend here every day and shared with you the latest/greatest posts. Gem version bumps, tutorials, blogs, happenings. Curated. Also with RSS support if you have a favorite reader. Nice.</p>
<h3 id="on_ruby---community-tooling"><a href="https://github.com/phoet/on_ruby">on_ruby</a> - Community Tooling</h3>
<p>This is very slick open-source tooling if you want to spin up a web front end for your Ruby User group, and a fair few rely on it. Consider pitching it at your local group!</p>
<h3 id="this-week-in-rails---news"><a href="https://rails-weekly.ongoodbits.com/">This week in Rails</a> - News</h3>
<p>PR’s, issues, discussion, so much is happening on Rails core every single day. How can we keep on top of it all? Thank goodness for ‘This week in Rails’, which condenses the changes into a handful of snippets each and every week. This is a Rails developer ‘must-subscribe’.</p>
<p>That’s all for now! Thanks for supporting Ruby and if I have missed something, let me know! I love checking out new resources!</p>Migrate your apps to the new community-maintained trix gem: ‘trix-rails’2018-08-21T14:34:09+00:002018-08-21T14:34:09+00:00https://schwad.github.io/ruby/rails/community/2018/08/21/new-community-maintained-trix-gem<p style="text-align:center"><img src="https://i.imgur.com/vwLzQIy.png" alt="New Horizons" /></p>
<p><a href="https://github.com/basecamp/trix">Trix</a> is a fantastic open-source WYSIWYG tool from the lovely folks at Basecamp. Thanks to their hard work, we can easily punch in rich text editing for our users in a text field or text area. It has also become a critical piece of technology used by companies like <a href="https://www.podia.com/">Podia</a> and <a href="https://www.oceanshq.com/">OceansHQ</a>.</p>
<p style="text-align:center"><img src="https://i.imgur.com/8eIg8Wy.png" alt="WYSIWYG" /></p>
<p>If you wanted to integrate <code class="highlighter-rouge">trix</code> seamlessly into your Rails app, there was a very handy <a href="https://github.com/maclover7/trix">Ruby Gem</a> that could get you going in no time flat. We are incredibly grateful to the maintainers who got this gem going that we rely on so much.</p>
<p>It is time to give back. <a href="https://github.com/maclover7/trix/issues/69">For reasons that I will not go into here, the gem was in need of community-driven support to continue</a>. After a <a href="https://github.com/maclover7/trix/issues/69">public discussion with users in the trix Ruby community</a>, <code class="highlighter-rouge">trix-rails</code> has been announced as the fully-maintained RubyGem for using trix in Rails.</p>
<p>Please feel free to <a href="https://github.com/kylefox/trix">stop on by and pitch in</a> or direct any issues/PRs here for future work on the trix gem.</p>
<p>Just want to migrate your app to the latest supported gem? Simply swap out trix in your gemfile for:</p>
<p><code class="highlighter-rouge">gem 'trix-rails', require: 'trix'</code></p>
<p>And you’re ready to go! Thanks again to the prior maintainers and basecamp for all your amazing work on trix!</p>My Favorite Ruby Community Resources2018-05-03T14:34:09+00:002018-05-03T14:34:09+00:00https://schwad.github.io/ruby/rails/community/resources/2018/05/03/my-favorite-ruby-community-resources<p style="text-align:center"><img src="https://i.imgur.com/khXOwRk.jpg" alt="Favorite" /></p>
<p>I don’t live near many rubyists.</p>
<p>Having spent my Ruby/Rails career in remote Montana and then in remote Cornwall (UK), I have been very lucky to craft and create software while enjoying being removed from the city life. I also get to work for a small, flexible company. The trade off? Almost all of my ‘Ruby’ networking and community has had to come from web-accessible resources.</p>
<p>I recently <a href="www.isleofruby.org">spoke at Isle of Ruby</a>(which will get its own post soon). This topic came up with some there. Following further discussions I decided to publish my favorite ruby resource for those of you in a similar position.</p>
<p>This list is by no means comprehensive and changes all the time, but it’s the sort of thing I wish I had access to from day one. Without further adieu….</p>
<h2 id="a-few-of-my-favorite-ruby-things">A few of my favorite (ruby) things</h2>
<ul>
<li>I post generally useful things I come across and ‘do not want to forget’ (i.e. more than a bookmark) on my page here: https://schwad.github.io/reading-list/</li>
</ul>
<h3 id="podcasts">Podcasts</h3>
<ul>
<li><a href="http://bikeshed.fm/">The Bikeshed</a> (Derek Prior, Sean Griffin and friends - very fun)</li>
<li><a href="https://devchat.tv/ruby-rogues">Ruby Rogues</a> (Possibly the longest running one, medium-technical)</li>
<li><a href="http://artofproductpodcast.com/">The Art of Product</a> (Ben Orenstein and Derek Reimer, both big Rubyists, often talk far beyond Ruby and about their careers)</li>
<li><a href="http://5by5.tv/rubyonrails">The Ruby on Rails Podcast</a> (Brittany Martin and Kyle Daigle and guests, very very enjoyable)</li>
<li><a href="http://giantrobots.fm/">Giant Robots Smashing into Other Giant Robots</a> (Put out by Thoughtbot - I used to listen to this a lot but it has gotten less and less Ruby based)</li>
<li><a href="https://ruby5.codeschool.com/">Ruby5</a> (This was discontinued in 2016 but is <em>great</em> if you want to hear about the past, with 5 minute quick Ruby community updates)</li>
</ul>
<h3 id="newslettersblogs">Newsletters/Blogs:</h3>
<ul>
<li><a href="https://rubyweekly.com/">RubyWeekly</a>. This is my bible. If I listen to or read nothing else I <em>always</em> read this. I remember the first time they shared a post of mine on here and I felt like a hero!</li>
<li><a href="https://www.rubytapas.com/">RubyTapas</a> by Avdi Grimm - he also runs several newsletters including one called ‘Brunch’</li>
<li><a href="https://www.schneems.com/">Schneems</a>! Really nice guy and big contributor, has a blog and newsletter. Very helpful stuff for me from community perspective</li>
<li><a href="https://tenderlovemaking.com/">Aaron Patterson</a> - He doesn’t write here much but as one of the big names his writings are great</li>
<li><a href="http://www.rubyguides.com/">Jesus Castello</a></li>
<li><a href="https://andycroll.com/ruby/stop-robots-crawlers-triggering-errors-rails/">Andy Croll</a> (who organizes Brighton Ruby Conf)</li>
<li><a href="https://www.driftingruby.com/">Drifting Ruby</a> - they are releasing pro-only videos sometimes now but this is my favorite screencast-er with weekly updates on really interesting stuff and I find it incredibly useful. One of the hosts of Ruby Rogues does this</li>
<li>Finally <a href="https://www.codetriage.com/">Code Triage</a>. Seriously, it really helped me go from ‘I never have done any open source help’ to making it a habit. I just get random notifications about old PRs and Issues and I read them. If they need a ‘bump’ I kindly write ‘Hey what’s happening here?’. And once in a while I can actually help from the technical perspective.</li>
</ul>
<p>Missing anything?</p>
<form action="https://www.getdrip.com/forms/275494850/submissions" method="post" data-drip-embedded-form="275494850">
<h3 data-drip-attribute="headline">Stay in Touch</h3>
<div data-drip-attribute="description">I like to write about Ruby and building things, typically once every month or so. Get an email when I have written something new.</div>
<div>
<label for="drip-email">Email Address</label><br />
<input type="email" id="drip-email" name="fields[email]" value="" />
</div>
<div>
<input type="submit" value="I Love Ruby too! 💎" data-drip-attribute="sign-up-button" />
</div>
</form>Coming to Terms with the ‘Prima Donna Method’ Smell2018-02-14T14:34:09+00:002018-02-14T14:34:09+00:00https://schwad.github.io/ruby/rails/code-quality/code-smells/2018/02/14/coming-to-terms-with-the-prima-donna-method-smell<!-- Drip -->
<script type="text/javascript">
var _dcq = _dcq || [];
var _dcs = _dcs || {};
_dcs.account = '2671646';
(function() {
var dc = document.createElement('script');
dc.type = 'text/javascript'; dc.async = true;
dc.src = '//tag.getdrip.com/2671646.js';
var s = document.getElementsByTagName('script')[0];
s.parentNode.insertBefore(dc, s);
})();
</script>
<!-- end Drip -->
<p style="text-align:center"><img src="http://i.imgur.com/iWKad22.jpg" alt="Facepalm" /></p>
<p>Oh man. I wrote this post originally as ‘In Defense of the Prima Donna Method Smell’. By the time I was done, the powerful words of David A. Black had brought me back to the light. Here’s the tale of my journey:</p>
<p>I have been a staunch advocate of enforcing code smell/quality standards in my work. Nothing makes me happier than requiring <a href="https://github.com/bbatsov/rubocop">rubocop</a>, <a href="https://github.com/troessner/reek">reek</a> and <a href="https://github.com/DamirSvrtan/fasterer">fasterer</a> to pass every PR. Heck I even occasionally like to unwind with a bottle of wine and <a href="https://github.com/whitesmith/rubycritic">Ruby Critic</a> to highlight all the bad decisions I’ve ever made.</p>
<p>But what happens when I disagree with a valid code smell?</p>
<p>The ‘Prima Donna Method’ code smell has been a settled Ruby convention <a href="http://davidablack.net/dablog.html#2007/8/15/bang-methods-or-danger-will-rubyist">for at least a decade</a>. It is a generally recognized component of <a href="http://www.rubydoc.info/github/troessner/reek/Reek/Smells/PrimaDonnaMethod">most major Ruby code quality tooling</a>.</p>
<p>Simply put, a ‘Prima Donna Method’ is one that has a ! suffix but with no bang-less partner. (Rails devs - think <code class="highlighter-rouge">#save</code> and <code class="highlighter-rouge">#save!</code>)</p>
<p>David A. Black of <a href="https://www.amazon.com/Well-Grounded-Rubyist-David-Black/dp/1617291692">‘The Well Grounded Rubyist’</a> fame eloquently articulates why this is a smell:</p>
<blockquote>
<p>The ! in method names that end with ! means, “This method is dangerous”—or, more precisely, this method is the “dangerous” version of an otherwise equivalent method, with the same name minus the !. “Danger” is relative; the ! doesn’t mean anything at all unless the method name it’s in corresponds to a similar but bang-less method name.</p>
<p>So, for example, gsub! is the dangerous version of gsub. exit! is the dangerous version of exit. flatten! is the dangerous version of flatten. And so forth.</p>
</blockquote>
<p>For those keeping score at home, an example violating this principle would be:</p>
<figure class="highlight"><pre><code class="language-ruby" data-lang="ruby"><span class="k">class</span> <span class="nc">Foo</span>
<span class="k">def</span> <span class="nf">bar!</span>
<span class="nb">puts</span> <span class="s1">'Bar!'</span>
<span class="k">end</span>
<span class="k">end</span></code></pre></figure>
<p>And a passing equivalent would be:</p>
<figure class="highlight"><pre><code class="language-ruby" data-lang="ruby"><span class="k">class</span> <span class="nc">Foo</span>
<span class="k">def</span> <span class="nf">bar</span>
<span class="nb">puts</span> <span class="s1">'Bar!'</span>
<span class="k">end</span>
<span class="k">def</span> <span class="nf">bar!</span>
<span class="nb">puts</span> <span class="s1">'Bar!'</span>
<span class="k">end</span>
<span class="k">end</span></code></pre></figure>
<p>Also note that this smell does not care about method content. It simply cares about the <strong>signal</strong> the method name sends with the bang. Developers require a common language for better programming experiences, and we expect certain things with how our methods are named.</p>
<p>However, during one of my wine-laden Ruby Critic sessions on a codebase, I discovered some violations on a few methods that would require one of the following resolutions:</p>
<ol>
<li>
<p>Create a companion method that I would never use</p>
</li>
<li>
<p>Ignore the smell linter via yaml configuration</p>
</li>
<li>
<p>Rename the method, without the bang</p>
</li>
</ol>
<p>Here’s the problem though: I felt <em>none of those solutions improve my codebase</em>. Ignoring smells is a ‘smell’ to me, adding pointless methods equally so, and renaming the method would take away from the articulation of the method for me.</p>
<p>The current dialect around bangs, I thought, had become more and more often a signal of ‘transformative’ dangerous types of behavior. I felt the following method did not deserve splitting out:</p>
<div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code>class Purchase &lt; ApplicationRecord
def void!
#whether or not you should use #update_column is a discussion for another post...
update_column(:void, true)
end
end
</code></pre></div></div>
<p>I thought that would be articulate enough as-is, and the bang would communicate to future developers on the fly that this is an action which changes the database row. So I went around penning my revelations and opinions to the community. However, the following further passages from Black really rung true with me:</p>
<blockquote>
<p>Don’t add ! to your destructive (receiver-changing) methods’ names, unless you consider the changing to be “dangerous” and you have a “non-dangerous” equivalent method without the !. If some arbitrary subset of destructive methods end with !, then the whole point of ! gets distorted and diluted, and ! ceases to convey any information whatsoever.</p>
<p>If you want to write a destructive method and you don’t think the name conveys destruction, you might be tempted to add a ! to make it clear. That’s not a good idea. If the name of a destructive method, without a !, does not connote destruction, then the name is wrong and cannot be repaired by slapping a ! on it.</p>
</blockquote>
<p>It’s easy for us to view criticism or code-smell failures from an egotistical vantage - ‘how could <em>I</em> be in the wrong here!? I am a <em>professional</em>!’. However sometimes it’s worth coming down off of your high horse and reconsidering your passionate position on a snippet of smelly code.</p>
<p>I got my original ‘signalling’ ideas crosswired. <em>Any method can be destructive</em>. The ! is solely to convey information for <strong>dangerous versions of existing methods</strong>.</p>
<form action="https://www.getdrip.com/forms/275494850/submissions" method="post" data-drip-embedded-form="275494850">
<h3 data-drip-attribute="headline">Stay in Touch</h3>
<div data-drip-attribute="description">I like to write about Ruby and building things, typically once every month or so. Get an email when I have written something new.</div>
<div>
<label for="drip-email">Email Address</label><br />
<input type="email" id="drip-email" name="fields[email]" value="" />
</div>
<div>
<input type="submit" value="I Love Ruby too! 💎" data-drip-attribute="sign-up-button" />
</div>
</form>Overhauling the PorkCast database in Rails2017-10-13T14:34:09+00:002017-10-13T14:34:09+00:00https://schwad.github.io/ruby/rails/database/2017/10/13/overhauling-the-porkcast-database-in-rails<p style="text-align:center"><img src="https://static.pexels.com/photos/577585/pexels-photo-577585.jpeg" alt="Data" /></p>
<p>PorkCasts, <a href="https://www.bozemandailychronicle.com/news/politics/porkcast-lawmaker-hopes-new-website-improves-government-transparency/article_f6f49d3a-eea8-5fde-a7f7-fa4b321a419d.html">one of my hallmark Rails applications,</a> turned two this year. It was the first application of its kind in Montana, relying on the State’s Socrata-based API for checkbook and credit card payments to expose state spending. It also allows users to set up ‘notifications’ to receive emails when a specific query receives public moneys.</p>
<p>As with many personal projects, 2015 saw the vast majority of hacking on this project and then it was left to run on its own. I finally have turned my eye back to it in 2017 and am making several significant improvements for ‘PorkCast 2.0’. For this post I want to focus on the dataset.</p>
<p>Before starting I want to evangelize the glory of <code class="highlighter-rouge">ProgressBar</code>. <a href="https://github.com/paul/progress_bar">This gem</a> is a must-have when running rake tasks or console commands that may take up a lot of work and time.</p>
<figure class="highlight"><pre><code class="language-ruby" data-lang="ruby"><span class="nb">require</span> <span class="s1">'progress_bar'</span>
<span class="n">bar</span> <span class="o">=</span> <span class="no">ProgressBar</span><span class="p">.</span><span class="nf">new</span><span class="p">(</span><span class="no">MyObject</span><span class="p">.</span><span class="nf">count</span><span class="p">)</span>
<span class="no">MyObject</span><span class="p">.</span><span class="nf">each</span> <span class="k">do</span> <span class="o">|</span><span class="n">obj</span><span class="o">|</span>
<span class="n">obj</span><span class="p">.</span><span class="nf">some_mutative_task!</span>
<span class="n">bar</span><span class="p">.</span><span class="nf">increment!</span>
<span class="k">end</span></code></pre></figure>
<p>This will give you a live terminal-based progress bar inclusive of time estimates for the task at hand. Don’t leave home without it.</p>
<h3 id="expanding-the-in-house-database">Expanding the in-house database</h3>
<p>The old system relied on the State of Montana API far too much. Whenever a user would search for a query, PorkCast would ping a request to MT and build a set of check and credit card payments from there.</p>
<p>Here’s what I didn’t like about that:</p>
<ol>
<li>The request cycle was incredibly slow (by developer terms) for the end user.</li>
<li>The data remained on the state side primarily, limiting our ability to run in-house analytics.</li>
<li>We had no ability to ‘audit’ state data, checking if payments were deleted or changed.</li>
</ol>
<p>I wanted to take all of the state data in my application and only ping the state for update purposes.</p>
<p>My Heroku DB would not support this (free tier is 10,000 rows). I knew I would need support for up to 10,000,000 rows. It was nerve-wracking, but by <a href="https://devcenter.heroku.com/articles/upgrading-heroku-postgres-databases">following the comprehensive heroku docs</a> I was able to upgrade without any issues. Now to bring the data in.</p>
<h3 id="importing-hundreds-of-thousands-of-rows-of-new-data">Importing hundreds of thousands of rows of new data</h3>
<p>PorkCast had not taken on new data in the better part of a year- and the State of Montana recently terminated their Socrata API license. I had no easy way to update and read in data. I went to <a href="https://transparency.mt.gov/">the state transparency website</a> and downloaded their files for payments in checks and credit cards for FY 2017 and FY 2018.</p>
<p>Fun fact, just because a file says <code class="highlighter-rouge">.csv</code> does <em>not</em> mean that it will play nice with the Ruby <code class="highlighter-rouge">CSV</code> library. After a few confused hours of debugging I broke down and opened the files in Excel. Turns out they were in <code class="highlighter-rouge">UTF-16</code> format- all I had to do was save them to vanilla CSV each and they worked fine…. Besides the fact that each file had a different approach to how they rendered payment dates (European and American date formats).</p>
<p>If you are able to edit your CSV rows down to just what you need, I heartily recommend <a href="https://github.com/zdennis/activerecord-import">using the activerecord-import gem.</a> Taking from examples from their wiki, this is how you can handle massive imports much, much faster:</p>
<figure class="highlight"><pre><code class="language-ruby" data-lang="ruby"><span class="n">columns</span> <span class="o">=</span> <span class="p">[</span> <span class="ss">:title</span><span class="p">,</span> <span class="ss">:author</span> <span class="p">]</span>
<span class="n">values</span> <span class="o">=</span> <span class="p">[</span> <span class="p">[</span><span class="s1">'Book1'</span><span class="p">,</span> <span class="s1">'FooManChu'</span><span class="p">],</span> <span class="p">[</span><span class="s1">'Book2'</span><span class="p">,</span> <span class="s1">'Bob Jones'</span><span class="p">]</span> <span class="p">]</span>
<span class="no">Book</span><span class="p">.</span><span class="nf">import</span> <span class="n">columns</span><span class="p">,</span> <span class="n">values</span>
<span class="no">Book</span><span class="p">.</span><span class="nf">import</span> <span class="n">columns</span><span class="p">,</span> <span class="n">values</span><span class="p">,</span> <span class="ss">:batch_size</span> <span class="o">=&gt;</span> <span class="mi">1000</span></code></pre></figure>
<h3 id="changing-the-internal-architecture">Changing the internal architecture</h3>
<p>The DB schema used to go:</p>
<p><code class="highlighter-rouge">Query belongs_to User</code>
<code class="highlighter-rouge">User has_many Queries</code></p>
<p>This created a problem, I only want one source of truth for queries instead of risking duplication if everyone searches ‘NICHOLAS R SCHWADERER’. To do so I created a ‘UserQuery’ object and set up queries and users to utilize it <a href="http://guides.rubyonrails.org/association_basics.html#the-has-many-through-association">with a has_many: through association</a>.</p>
<p>To get this up to speed takes three migrations:</p>
<ol>
<li>Generate the first batch of UserQuery objects to mimic the original associations.</li>
<li>Delete the duplicate queries.</li>
<li>Iterate over the UserQuery objects and point to the only remaining query.</li>
</ol>
<p>The same deduping would be needed for checks.</p>
<h3 id="the-saga-of-deduping-and-killing-orphan-queries">The saga of deduping and killing orphan queries</h3>
<p>The major problem I had now as mentioned earlier was deduping, reassigning and cleanup up the Check, CreditCard and Query tables in the database. This data was the core truth of the system so before I committed any of these changes I backed up my db on Heroku.</p>
<p>First, to alter my production database I utilized <a href="https://devcenter.heroku.com/articles/heroku-postgresql#pg-push-and-pg-pull">herou pg:push and pg:pull</a> for a slick interface to push and pull my db.</p>
<p>Second, I silenced outputs. I just wanted to see the progress bar, so any code I ran from here I did within the block:</p>
<figure class="highlight"><pre><code class="language-ruby" data-lang="ruby"><span class="no">ActiveRecord</span><span class="o">::</span><span class="no">Base</span><span class="p">.</span><span class="nf">logger</span><span class="p">.</span><span class="nf">silence</span> <span class="k">do</span>
<span class="c1"># My Code</span>
<span class="k">end</span></code></pre></figure>
<p>Then- to be safe- I added a ‘name’ column to UserQuery objects and migrated their query’s name over. Consider it a safeguard.</p>
<figure class="highlight"><pre><code class="language-ruby" data-lang="ruby"><span class="no">UserQuery</span><span class="p">.</span><span class="nf">all</span><span class="p">.</span><span class="nf">each</span> <span class="k">do</span> <span class="o">|</span><span class="n">uq</span><span class="o">|</span>
<span class="nb">puts</span> <span class="s1">'Now assigning user query names.'</span>
<span class="n">uq</span><span class="p">.</span><span class="nf">name</span> <span class="o">=</span> <span class="n">uq</span><span class="p">.</span><span class="nf">query</span><span class="p">.</span><span class="nf">content</span>
<span class="n">uq</span><span class="p">.</span><span class="nf">save!</span>
<span class="k">end</span></code></pre></figure>
<p>Next I killed all old ‘empty’ queries. These were typically old searches by users that didn’t match anything. From now on all our queries will point to actual real entities. This killed about 12,500 queries.</p>
<figure class="highlight"><pre><code class="language-ruby" data-lang="ruby"><span class="no">Query</span><span class="p">.</span><span class="nf">all</span><span class="p">.</span><span class="nf">includes</span><span class="p">(</span><span class="ss">:checks</span><span class="p">,</span> <span class="ss">:credit_cards</span><span class="p">).</span><span class="nf">where</span><span class="p">(</span><span class="ss">checks: </span><span class="p">{</span> <span class="ss">id: </span><span class="kp">nil</span> <span class="p">}).</span><span class="nf">where</span><span class="p">(</span><span class="ss">credit_cards: </span><span class="p">{</span> <span class="ss">id: </span><span class="kp">nil</span> <span class="p">}).</span><span class="nf">destroy_all</span></code></pre></figure>
<p>Then I ran a dedupe against queries based on their name. Pretty straightforward. Afterwards I reassigned all outstanding UserQuery objects to the remaining queries.</p>
<figure class="highlight"><pre><code class="language-ruby" data-lang="ruby"><span class="n">bar</span> <span class="o">=</span> <span class="no">ProgressBar</span><span class="p">.</span><span class="nf">new</span><span class="p">(</span><span class="no">UserQuery</span><span class="p">.</span><span class="nf">count</span><span class="p">)</span>
<span class="no">UserQuery</span><span class="p">.</span><span class="nf">all</span><span class="p">.</span><span class="nf">each</span> <span class="k">do</span> <span class="o">|</span><span class="n">uq</span><span class="o">|</span>
<span class="k">begin</span>
<span class="k">if</span> <span class="no">Query</span><span class="p">.</span><span class="nf">where</span><span class="p">(</span><span class="ss">id: </span><span class="n">uq</span><span class="p">.</span><span class="nf">query_id</span><span class="p">).</span><span class="nf">count</span> <span class="o">==</span> <span class="mi">0</span>
<span class="n">uq</span><span class="p">.</span><span class="nf">query_id</span> <span class="o">=</span> <span class="no">Query</span><span class="p">.</span><span class="nf">find_by_content</span><span class="p">(</span><span class="n">uq</span><span class="p">.</span><span class="nf">name</span><span class="p">)</span>
<span class="n">uq</span><span class="p">.</span><span class="nf">save</span>
<span class="k">end</span>
<span class="k">rescue</span> <span class="o">=&gt;</span> <span class="n">e</span>
<span class="nb">puts</span> <span class="s2">"had a slight oops on UQ </span><span class="si">#{</span><span class="n">uq</span><span class="p">.</span><span class="nf">id</span><span class="si">}</span><span class="s2"> of </span><span class="si">#{</span><span class="n">e</span><span class="p">.</span><span class="nf">message</span><span class="si">}</span><span class="s2">"</span>
<span class="k">end</span>
<span class="k">end</span></code></pre></figure>
<p>And I did the same for checks and credit cards.</p>
<figure class="highlight"><pre><code class="language-ruby" data-lang="ruby"><span class="n">bar</span> <span class="o">=</span> <span class="no">ProgressBar</span><span class="p">.</span><span class="nf">new</span><span class="p">(</span><span class="no">Check</span><span class="p">.</span><span class="nf">count</span><span class="p">)</span>
<span class="no">Check</span><span class="p">.</span><span class="nf">all</span><span class="p">.</span><span class="nf">each</span> <span class="k">do</span> <span class="o">|</span><span class="n">c</span><span class="o">|</span>
<span class="k">begin</span>
<span class="k">if</span> <span class="no">Query</span><span class="p">.</span><span class="nf">where</span><span class="p">(</span><span class="ss">id: </span><span class="n">c</span><span class="p">.</span><span class="nf">query_id</span><span class="p">).</span><span class="nf">count</span> <span class="o">==</span> <span class="mi">0</span>
<span class="n">c</span><span class="p">.</span><span class="nf">query_id</span> <span class="o">=</span> <span class="no">Query</span><span class="p">.</span><span class="nf">find_by_content</span><span class="p">(</span><span class="n">c</span><span class="p">.</span><span class="nf">payee</span><span class="p">)</span>
<span class="n">c</span><span class="p">.</span><span class="nf">save</span>
<span class="k">end</span>
<span class="k">rescue</span> <span class="o">=&gt;</span> <span class="n">e</span>
<span class="nb">puts</span> <span class="s2">"had a slight oops on UQ </span><span class="si">#{</span><span class="n">uq</span><span class="p">.</span><span class="nf">id</span><span class="si">}</span><span class="s2"> of </span><span class="si">#{</span><span class="n">e</span><span class="p">.</span><span class="nf">message</span><span class="si">}</span><span class="s2">"</span>
<span class="k">end</span>
<span class="n">bar</span><span class="p">.</span><span class="nf">increment!</span>
<span class="k">end</span></code></pre></figure>
<p>Here’s the real fun. After everything was appropriately reassigned, I still had an issue of duplicate checks and credit cards from a couple raw imports over the last year that have some level of overlap. Deduping records that aren’t 100% identical when you have millions of rows is <strong>no easy task</strong>. I approached this with an approach garnered in a <a href="https://stackoverflow.com/questions/14124212/remove-duplicate-records-based-on-multiple-columns">great SO post I had uncovered</a>. All I had to do was select the columns I wanted to check against the dedupe.</p>
<figure class="highlight"><pre><code class="language-ruby" data-lang="ruby"><span class="n">ary</span> <span class="o">=</span> <span class="p">[]</span>
<span class="n">grouped</span> <span class="o">=</span> <span class="no">Check</span><span class="p">.</span><span class="nf">all</span><span class="p">.</span><span class="nf">group_by</span><span class="p">{</span><span class="o">|</span><span class="n">check</span><span class="o">|</span> <span class="p">[</span><span class="n">check</span><span class="p">.</span><span class="nf">department</span><span class="p">,</span><span class="n">check</span><span class="p">.</span><span class="nf">payee</span><span class="p">,</span><span class="n">check</span><span class="p">.</span><span class="nf">payment_category</span><span class="p">,</span><span class="n">check</span><span class="p">.</span><span class="nf">amount</span><span class="p">,</span><span class="n">check</span><span class="p">.</span><span class="nf">payment_date</span><span class="p">]</span> <span class="p">}</span>
<span class="n">bar</span> <span class="o">=</span> <span class="no">ProgressBar</span><span class="p">.</span><span class="nf">new</span><span class="p">(</span><span class="n">grouped</span><span class="p">.</span><span class="nf">values</span><span class="p">.</span><span class="nf">count</span><span class="p">)</span>
<span class="n">grouped</span><span class="p">.</span><span class="nf">values</span><span class="p">.</span><span class="nf">each</span> <span class="k">do</span> <span class="o">|</span><span class="n">repeats</span><span class="o">|</span>
<span class="n">original</span> <span class="o">=</span> <span class="n">repeats</span><span class="p">.</span><span class="nf">shift</span>
<span class="n">repeats</span><span class="p">.</span><span class="nf">each</span><span class="p">{</span><span class="o">|</span><span class="n">double</span><span class="o">|</span> <span class="n">ary</span> <span class="o">&lt;&lt;</span> <span class="n">double</span><span class="p">.</span><span class="nf">id</span><span class="p">}</span>
<span class="n">bar</span><span class="p">.</span><span class="nf">increment!</span>
<span class="k">end</span>
<span class="nb">puts</span> <span class="s2">"To delete </span><span class="si">#{</span><span class="n">ary</span><span class="p">.</span><span class="nf">length</span><span class="si">}</span><span class="s2"> checks"</span>
<span class="no">Check</span><span class="p">.</span><span class="nf">delete</span><span class="p">(</span><span class="n">ary</span><span class="p">)</span></code></pre></figure>
<p>Once all of this was wrapped up, I finally had the db how I wanted and could <code class="highlighter-rouge">pg:push</code> the db live.</p>
<h3 id="including-elasticsearch-in-the-stack">Including Elasticsearch in the stack</h3>
<p>On the original version of PorkCast, I home-rolled all my searching and auto-complete logic. That’s fine for small stuff, but for a dataset of this size and larger, I really wanted to give an elasticsearch integration a try.</p>
<p>Elasticsearch is no small beast to play with. If you look at <code class="highlighter-rouge">remoteok.io</code> a lot of job postings specifically mention this toolset. I was intimidated. Luckily, I found a fantastic ruby gem with great documentation on hooking up elasticsearch functionality and deploying to heroku: <a href="https://github.com/ankane/searchkick">Searchkick</a>.</p>
<p>Once I followed their docs all I had to do was run <code class="highlighter-rouge">Query.reindex</code> in the console and I was good to go. It was shocking to me how lightning fast it is- I even allow autocomplete suggestions on every keystroke with little to no pain on the server end. Thank goodness for <a href="https://www.rubyweekly.com">Ruby Weekly</a> for pointing me to searchkick.</p>
<p>I reckon in the next month or so I’ll have a shorter post highlighting all the new components of PorkCast 2.0 once it’s live.</p>
<!-- Drip -->
<script type="text/javascript">
var _dcq = _dcq || [];
var _dcs = _dcs || {};
_dcs.account = '2671646';
(function() {
var dc = document.createElement('script');
dc.type = 'text/javascript'; dc.async = true;
dc.src = '//tag.getdrip.com/2671646.js';
var s = document.getElementsByTagName('script')[0];
s.parentNode.insertBefore(dc, s);
})();
</script>
<!-- end Drip -->
<form action="https://www.getdrip.com/forms/275494850/submissions" method="post" data-drip-embedded-form="275494850">
<h3 data-drip-attribute="headline">Stay in Touch</h3>
<div data-drip-attribute="description">I like to write about Ruby and building things, typically once every month or so. Get an email when I have written something new.</div>
<div>
<label for="drip-email">Email Address</label><br />
<input type="email" id="drip-email" name="fields[email]" value="" />
</div>
<div>
<input type="submit" value="I Love Ruby too! 💎" data-drip-attribute="sign-up-button" />
</div>
</form>Take care when using `render` in Rails2017-09-05T14:34:09+00:002017-09-05T14:34:09+00:00https://schwad.github.io/ruby/rails/controllers/2017/09/05/take-care-when-using-render-in-rails<p style="text-align:center"><img src="http://i.imgur.com/RHhzGMv.jpg" alt="Double" /></p>
<p>The more I experiment with other technologies, the more I realize what a joy it is to work with Rails and Ruby every single day.</p>
<p>I take for granted the baked-in convention-over-configuration ethos, which allows developers to maximize their efforts with genuine building and creativity.</p>
<p>Take for example the following:</p>
<h3 id="implicit-rendering">Implicit rendering</h3>
<p>When spinning up a new action in ActionController, you do not need to specify what template to render. As long as the namespaces match and are found in <code class="highlighter-rouge">app/views</code>, your application will do the work for you. If you stay RESTful on a CRUD app you may rarely if ever find yourself manually rendering templates.</p>
<script src="https://gist.github.com/e4cc7c3bb19a9c0d412f5cf306957c31.js"> </script>
<p>See? It knows to spit out the associated view. This is the kind of joy you experience from day one with the framework.</p>
<h3 id="explicit-rendering">Explicit rendering</h3>
<p>There will be times when we stray as we continue building larger applications. That’s okay though! Rails is convention <strong>over</strong> configuration, not the banishment of configuration altogether. In that case we can send the template explicitly down….</p>
<script src="https://gist.github.com/2c93aabc5a94dfc57b5e3a41f012b91e.js"> </script>
<p>… and Rails knows what we’re about.</p>
<h3 id="extra-curricular-activity">Extra curricular activity</h3>
<p>That doesn’t mean we can’t overlook something big. It’s important to note the <strong>easily-missed</strong> case where we can be executing unexpected code. Take the following example:</p>
<script src="https://gist.github.com/fb15697bc0d44d60b37d665deb649951.js"> </script>
<p>It may be obvious from such a small controller action, but this can easily be missed as controllers get more fat. All code after a <code class="highlighter-rouge">redirect</code> or <code class="highlighter-rouge">render</code> <strong>is still executed</strong>. That means in this case we see this page:</p>
<p style="text-align:center"><img src="http://i.imgur.com/ji4y7TT.png" alt="Double" /></p>
<p>But if we refresh we notice that our title indeed <em>was</em> updated behind the scenes.</p>
<p style="text-align:center"><img src="http://i.imgur.com/2d7hB1Q.png" alt="Double" /></p>
<p>While building out controllers and especially as they get larger, be sure to take care to consider code that may be executed after.</p>
<h3 id="handling-doublerendererror">Handling DoubleRenderError</h3>
<p>Worth remembering is that <code class="highlighter-rouge">render</code> or <code class="highlighter-rouge">redirect</code> code is executed more than once. See below:</p>
<script src="https://gist.github.com/5c8d5c6bda0e3008c23d9cb6c62f2045.js"> </script>
<p>You’ve probably encountered this error a fair few times yourself. Most likely as controllers are growing. If you find yourself unable to remove the render or redirect (which I recommend trying first) you can resolve this by calling <code class="highlighter-rouge">and return</code> after the render is hit.</p>
<script src="https://gist.github.com/a279b21a319d8c8f4035029922e53b4f.js"> </script>
<p>This also precludes all later code from executing, which is a handy tool in the event that you not only want to prevent a DoubleRenderError, but stop later code from executing.</p>
<p>When we visit <code class="highlighter-rouge">'/books/blocks_double_render_error'</code> we can clearly see that the code has not executed on the title attribute.</p>
<p style="text-align:center"><img src="https://i.imgur.com/aAa8NtL.png" alt="Double" /></p>
<h3 id="conclusion">Conclusion</h3>
<p>If you want to have a play with this yourself, I fired up a repo <a href="https://github.com/Schwad/be_careful_how_you_render/blob/master/app/controllers/books_controller.rb">with the example code</a> that you can access.</p>
<p>For a deeper dive on this, I heartily recommend <a href="https://leanpub.com/tr5w">The Rails 5 Way</a> by <a href="https://twitter.com/obie">Obie Fernandez</a>. It is my absolute favorite Rails 5 reference to date.</p>
<!-- Drip -->
<script type="text/javascript">
var _dcq = _dcq || [];
var _dcs = _dcs || {};
_dcs.account = '2671646';
(function() {
var dc = document.createElement('script');
dc.type = 'text/javascript'; dc.async = true;
dc.src = '//tag.getdrip.com/2671646.js';
var s = document.getElementsByTagName('script')[0];
s.parentNode.insertBefore(dc, s);
})();
</script>
<!-- end Drip -->
<form action="https://www.getdrip.com/forms/275494850/submissions" method="post" data-drip-embedded-form="275494850">
<h3 data-drip-attribute="headline">Stay in Touch</h3>
<div data-drip-attribute="description">I like to write about Ruby and building things, typically once every month or so. Get an email when I have written something new.</div>
<div>
<label for="drip-email">Email Address</label><br />
<input type="email" id="drip-email" name="fields[email]" value="" />
</div>
<div>
<input type="submit" value="I Love Ruby too! 💎" data-drip-attribute="sign-up-button" />
</div>
</form>How I got RSpec to boot 50 times faster2017-08-14T14:34:09+00:002017-08-14T14:34:09+00:00https://schwad.github.io/ruby/rails/testing/2017/08/14/50-times-faster-rspec-loading<p style="text-align:center"><img src="http://i.imgur.com/A5N2uos.jpg" alt="Speed" /></p>
<p>TDD was getting painful. Switching back and forth from my terminal to text editor running my latest RSpec tests saw me spending way too much time waiting not for my tests to run, but RSpec to load.</p>
<p>Here is an example running RSpec with one new test packaged with a feature:</p>
<div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code>Finished in 48.19 seconds (files took 33.15 seconds to load)
1 example, 0 failures
</code></pre></div></div>
<p>Good <em>lord</em>! I understand the 15 seconds as this was quite a hefty feature test, but waiting 30 extra seconds every time I want to check the spec, it’s been adding up. And I want to see ways if I can improve this. My first port of call was the content of what was getting loaded - obviously that must correlate to load times.</p>
<p>I thought it might be my gemset bloating. So, I checked.</p>
<p><code class="highlighter-rouge"> bundle | wc -l</code>
<code class="highlighter-rouge">#=&gt; 210</code>
<code class="highlighter-rouge">gem list -q | wc -l</code>
<code class="highlighter-rouge">#=&gt; 420</code></p>
<p>Yep, I’m relying on almost double the number of gems in my local gemset compared to bundle. Let’s fix that. There’s a great guide to setting up a new gemset with the rvm docs here https://rvm.io/gemsets/using</p>
<p>Following that, I went around to setting up a new gemset:</p>
<div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code>rvm gemset create schwad
#=&gt; ruby-2.3.3 - #gemset created /Users/nickschwaderer/.rvm/gems/ruby-2.3.3@schwad
#=&gt; ruby-2.3.3 - #generating schwad wrappers........
rvm gemset use schwad
#=&gt; Using ruby-2.3.3 with gemset schwad
rvm use 2.3.3@schwad
#=&gt; Using /Users/nickschwaderer/.rvm/gems/ruby-2.3.3 with gemset schwad
rvm use 2.3.3@schwad --default
#=&gt; Using /Users/nickschwaderer/.rvm/gems/ruby-2.3.3 with gemset schwad
gem list -q | wc -l
#=&gt; 42
</code></pre></div></div>
<p>Shwing! Lowered number of gems. Now to rebundle:</p>
<p><code class="highlighter-rouge">gem install bundler</code>
<code class="highlighter-rouge">bundle install</code>
<code class="highlighter-rouge">gem list -q | wc -l</code>
<code class="highlighter-rouge">#=&gt; 233</code></p>
<p>Great! even after bundling I’ve chopped down unused dependencies for this gemset. Now to test… Does anything speed up here?</p>
<div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code>Finished in 39.19 seconds (files took 38.15 seconds to load)
1 example, 0 failures
</code></pre></div></div>
<p>dang.</p>
<p>nope.</p>
<p>The only speed improvement was against the actual test when I switched from a full feature test to a <code class="highlighter-rouge">true</code> assertion while focusing on load times.</p>
<p>Despite running this spec and switching gemsets multiple times, even opening a new terminal and doing so, no meaningful change. So my boot time must be from something other than my local gems.</p>
<p>After digging around, I realized that reducing the burden on the load wasn’t the only way to achieve speed. If I’m running the same few tests over and over while working in a TDD fashion, <code class="highlighter-rouge">preloading</code> them may be the way forward like I do with the Rails console.</p>
<p>In my development/test group, I added the spring-commands-rspec gem found here: https://github.com/jonleighton/spring-commands-rspec . Then I ran <code class="highlighter-rouge">bundle exec spring binstub rspec</code> to generate <code class="highlighter-rouge">bin/rspec</code>. I knew spring worked well for my rails server, would it work well for loading rspec?</p>
<p><code class="highlighter-rouge">Finished in 1.39 seconds (files took 0.52567 seconds to load)</code></p>
<p><strong>HOLY SWEET SACCHARINE JEHOZAFAT!!!!</strong></p>
<p>This had to be a mistake. Ran it again, and again, and got the speed boost that <code class="highlighter-rouge">spring</code> provides by keeping things loaded for me.</p>
<p>This small tweak is saving me countless hours over the work cycle and seriously helped lower the pain points of proper TDD workflow.</p>
<!-- Drip -->
<script type="text/javascript">
var _dcq = _dcq || [];
var _dcs = _dcs || {};
_dcs.account = '2671646';
(function() {
var dc = document.createElement('script');
dc.type = 'text/javascript'; dc.async = true;
dc.src = '//tag.getdrip.com/2671646.js';
var s = document.getElementsByTagName('script')[0];
s.parentNode.insertBefore(dc, s);
})();
</script>
<!-- end Drip -->
<form action="https://www.getdrip.com/forms/275494850/submissions" method="post" data-drip-embedded-form="275494850">
<h3 data-drip-attribute="headline">Stay in Touch</h3>
<div data-drip-attribute="description">I like to write about Ruby and building things, typically once every month or so. Get an email when I have written something new.</div>
<div>
<label for="drip-email">Email Address</label><br />
<input type="email" id="drip-email" name="fields[email]" value="" />
</div>
<div>
<input type="submit" value="I Love Ruby too! 💎" data-drip-attribute="sign-up-button" />
</div>
</form>