2025-02-12
Rails has a built in mechanism for token authentication, and it’s documented in the Rails Guides.
Rails has a built in mechanism for token authentication, and it’s documented in the Rails Guides.
It is possible to set a fallback value for a missing environment variable in bash.
I needed this because the KAMAL_DESTINATION
environment variable may or may not be present in kamal deploy hooks.
# .kamal/hooks/post-deploy
bundle exec honeybadger deploy\
--repository="https://github.com/danott/some-repo"\
--revision="$KAMAL_VERSION"\
--environment="${KAMAL_DESTINATION:-production}"
Rails has a built in route for viewing notes.
bin/rails notes
in the consolehttp://localhost:3000/rails/info/notes
in the browserbrctl
is a command line utility for managing the CloudDocs (iCloud) daemon.
bctrl status | grep "somefile.ext"
could be useful for checking the status of a particular file.
I’ve been building a system that imports a lot of records from another system. The items from the other system have stable identifiers, but many other attributes will change.
In the past I’ve handled this scenario by iterating on each record, and individually “upsetting” into the local database. It would look something like
entries = RemoteSystem.new.entries
entries.each do |entry|
attributes = entry_attributes_from_remote_system(entry)
Entry.find_or_initialize_by(identifier: attributes.fetch("identifier").update(attributes)
end
This works fine and good, but I learned there’s a better way! Rails 6 introduced upsert_all. With this new method, many round trips to the database are replaced with one command.
entries = RemoteSystem.new.entries
entries_attributes = entries.map { |entry| entry_attributes_from_remote_system(entry) }
Entry.upsert_all(entries_attributes, unique_by: %w[identifier])
The one gotcha I’ve found so far, is that it fails if entries_attributes
is an empty array. Easily mitigated with a presence check.
Entry.upsert_all(entries_attributes, unique_by: %w[identifier]) unless entries_attributes.blank?
The Big Binary blog post has a lot of great information on usage.
I needed to rebuild some git history today. It’s never a fun task.
What I found while doing it, is that I was losing merge commits. I found this out to late, after taking a much less efficient approach. But if I ever encounter this problem in the future, the --keep-empty
flag will be helpful. As in
git rebase -interactive --keep-empty upstream
I built a Rails mailer for the first time in a very long time today. Revisiting the docs, I was greeted with a signature I didn’t recall from the past.
Mailer.with(some: "params", set: "this way").email_name.deliver_later
In the past, I’d always invoked mailers with
Mailer.email_name(some: "params", set: "this way").deliver_later
The with
message feels very aligned with ActiveJob.set
. For things that are needed on all mailers, like the recipient, I like standardizing on this approach for communicating params into the mailer.
Rails.env.test?
is always preferable to writing Rails.env == "test"
. The behavior that powers this predicate method is the ActiveSupport::StringInquirer
class.
This is not new information. But what was new, is finding the .inquiry
method that is added to a whole bunch of objects, including strings and arrays..
"test".inquiry.test?
%w[this that other].inquiry.other?
Neat!
Thanks to my partner in code, I learned that you can change the character that begins a comment in a Git commit message.
Commands such as
commit
andtag
that let you edit messages consider a line that begins with this character commented, and removes them after the editor returns (default #).If set to “auto”,
git-commit
would select a character that is not the beginning character of any line in existing commit messages.
I’m often writing Markdown in my commit messages, to leverage their legibility in other contexts. Before this configuration, headings were off limits. Now that I’ve changed my configuration with git config --global core.commandChar ";"
, they’re gonna be all over the place.
A byte order mark is an optional character that may appear at the beginning of a text stream. The unicode character U+FEFF
can be used to signal several things to a program reading the text.
My program reading the text is Ruby’s JSON.parse
. The text being read a JSON payload from the Pinboard API.
A helpful email exchange with Pinboard support is what pointed me in the right direction. A recent server upgrade began inserting the byte order mark where it wasn’t present before. It sounds like this insertion is going to be removed, because it makes the raw JSON payloads un-parsable by JSON.parse
in both Ruby and JavaScript.
In the meantime, I wanted to get my parsing fixed, so I could keep my Pinboard powered links up-to-date. With the tip from Pinboard support and some StackOverflow I got my JSON parsing fixed.
def load_remote_json
uri = URI("https://api.pinboard.in/v1/posts/all?tag=danott.co&format=json&auth_token=#{auth_token}")
body = Net::HTTP.get(uri)
+ body = strip_byte_order_mark(body)
JSON.parse(body)
end
+ def strip_byte_order_mark(potentially_unparsable)
+ potentially_unparsable.dup.sub("\xEF\xBB\xBF".force_encoding("UTF-8"), "")
+ end
This experience highlighted the tradeoffs of using vcr for tests. On the positive side, I had a cassette recording that captured the old API response. This allowed me to diff the old response and the new response to dig down and find what changed. On the negative side, I didn’t encounter the failure in parsing until it broke my link importing in production.
Tradeoffs.
Needing to reduce a pathname into the filename without it’s extension is something I need to do often. But not too often. Just often enough to forget how I last did it, and clobber together a solution anew.
So this time I’m writing down the briefest solution I’ve found in Ruby, in hopes that it’ll commit to my memory.
require "pathname"
pathname = Pathname.new("~/some/path/to/the/mountains.jpg")
pathname.basename(pathname.extname).to_s # => "mountains"
Pathname is a great tool in the standard library.
Sometimes you install one gem.
gem install bundler
Sometimes you install it with a specific version.
gem install bundler -v "2.0.2"
Sometimes you install multiple gems.
gem install bundler minitest
But what do you do if you need to install multiple gems with specific versions? It is possible with a special syntax!
gem install "bundler:2.0.2" "minitest:5.13.0"
Something I really like from React Native is the global variable __DEV__
. Being able to do things only in the development environment is quite handy. This concept is not unique to React Native, but that’s where I was introduced to it.
I’ve found myself in need of a similar strategy while building this static site in Rails. I have some dynamic interactions that I can use to curate content on my own machine, but I don’t want those scripts bloating the static build that is deployed to production.
This can be achived in Rails with webpacker using Webpack’s DefinePlugin!
// config/webpacker/environment.js
const { environment } = require("@rails/webpacker")
const webpack = require("webpack")
environment.plugins.prepend(
"Define",
new webpack.DefinePlugin({
STATIC: process.env.NODE_ENV === "production",
}),
)
module.exports = environment
Rails 6 introduces a new auto loader called zeitwork. The literature has me convinced transitioning to this new loader will be worth the effort. The legacy of the Rails apps we’ve built has us opting for the :classic
loader in the immediate.
A nice thing about using :classic
, is that Rails provides some deprecations that point toward getting ready for :zeitwork
. As an example, autoloading constants in an initializer (config/initializers/[something].rb
) emits a deprecation warning in Rails 6.
DEPRECATION WARNING: Initialization autoloaded the constants Sortable, Foldable, and Launderable.
Being able to do this is deprecated. Autoloading during initialization is going to be an error condition in future versions of Rails.
Reloading does not reboot the application, and therefore code executed during initialization does not run again. So, if you reload Sortable, for example, the expected changes won't be reflected in that stale Class object.
`config.autoloader` is set to `classic`. These autoloaded constants would have been unloaded if `config.autoloader` had been set to `:zeitwerk`.
Please, check the "Autoloading and Reloading Constants" guide for solutions.
Following the Autoloading and Reloading Constants guide, and some supplementary Duck Duck Go’ing, I learned about the Rails.configuration.to_prepare API. Where initializers run once when the app is booting, blocks passed to to_prepare
will be run before every request in development, and once before eager loading in production.
For a handful of constants that are being autoloaded in an initializer, using to_prepare
did the trick.
-ActiveRecord::Base.send :include, Sortable
+Rails.configuration.to_prepare { ActiveRecord::Base.send :include, Sortable }
I’m intentionally slow to script things away in my day-to-day development. I understand the benefits of scripting away repetitive tasks. But I’ve found that they come at the cost of empathy.
I used to have an alias of be
for running bundle exec
. When I’d pair with newer developers, they’d begin to think that be
is a command they should know, when in fact it was a customization they’d need to borrow. So I’ve formed the habit of always typing out bundle exec
.
It takes a little more time. But when someone is looking over my shoulder, they’re learning how to do do the thing rather than learning my abstraction about how to do the thing.
While authoring a very boring HTML form I learned that you do not need a for
/id
pair on a label that is wrapping a radio input.
-<label for="radio_option_1">
- <input id="radio_option_1" type="radio" name="cheese" value="cheddar"> Cheddar
+<label>
+ <input type="radio" name="cheese" value="cheddar"> Cheddar
React Native’s <StatusBar />
component behaves similarly to <Helmet />
from react-helmet. Render them anywhere in the tree. Every time an element is rendered, it’s props get pushed onto the top of a stack that will reconcile as a cascade of props for imperatively updating outside values.
The source of StatusBar.js
was particularly helpful, because I discovered it just as I was arriving at a near-identical solution for doing something similar in an app I’m working on.
git rebase --exec
is a handy tool for ensuring that each commit is keeping the tests passing.
Ensuring that each commit keeps the tests passing is in service of an ideal I’ve been pursuing. I don’t like submitting commits with the phrase “fix tests” in the description. I like refactoring old functionality or introducing new functionality under green tests.
To do this, I tend to work in two phases lately.
Phase one is an exploratory branch where I’m figuring things out. This is me thrashing through the jungle with a machete.
Phase two is a refined branch, where I’m communicating to others what I figured out. This is more surgical with detailed commits, explaning what changed, why, and alternatives that were considered in my exploratory thrashing branch.
Before submitting phase two for consideration, I’m starting to get in the habit of making sure the tests passed each step of the way.
$ git rebase --exec "bin/rails test" master
That will run the Rails tests on every commit that contributed to the current branch.
React’s Developer Tools are accessible from Safari!
For the last three years I’ve been developing day-to-day in Safari. Whenver this practice comes up in conversation the first question is “what about React Developer Tools?” Until today my answer was to drop into Chrome.
Today I discovered that react-devtools
can be launched as a standalone application that can be connected to.
I wired this up in my Rails app with some development only logic.
<% # app/views/application.html.erb %>
<% if Rails.env.development? && ENV["CONNECT_TO_REACT_DEVTOOLS"] == "yep" %>
<%= javascript_include_tag "http://localhost:8097" %>
<% end %>
With this in place, starting a Rails server with the appropriate environment flag does the trick. bin/rails server CONNECT_TO_REACT_DEVTOOLS=yep
Updating for security vulnerabilities with yarn can be tricky. For example, I got a Github warning that my version of js-yaml
needed to be updated. js-yaml
does not appear in my package.json
. It is one of my dependencies’ dependencies.
yarn update js-yaml@secure-version
adds js-yaml
into my dependencies, which is not what I want to communicate to the team.
Trying to solve for this communication problem brought me to Yarn’s selective dependency resolutions. This seems to fit the exact bill of what I’m trying to achieve. Among the reason’s to use selective dependency resolution is listed:
A sub-dependency of your project got an important security update and you don’t want to wait for your direct-dependency to issue a minimum version update.
Force yarn.lock
to update appropriately, without communicating to a future maintainer that this is actually a dependency of our app. Works on my machine.
Use date.to_s(:db)
when you need to use a date in a Rails YAML fixture. My muscle memory reached for date.format(:db)
, but that’s wrong. It’s .to_s
cookie_monster:
last_wanted_cookies_at: <%= 1.second.ago.to_s(:db) %>
When testing ActiveJob
, jobs performed with SomeJob.perform_now
will not show up in the performed_jobs
test helper method.
Today I was attempting to validate that three variables all held the same value. My clever approach was:
a = 1
b = 1
c = nil
[a, b, c].uniq.one?
I expected that to return false
. It was returning true
.
🤔
Showing my reasoning, elementary math style:
[a, b, c].uniq.one?
# becomes =>
[1, 1, nil].uniq.one?
# becomes =>
[1, nil].one?
There are two values, right? Here’s my mistake. In my quest for object-oriented-message-sending-purity I interpreted one?
to be about the size of the array. But reading the docs, I’m reminded it’s not a message about the size of the array. It’s a message that passes each item in the array to a block, and returns true if exactly one of those return values is truthy. Without an explicit block, the implicit block is the element itself. 1
is truty. nil
is not, so yes, there is one truthy value.
What I really wanted is [1, nil].count == 1
. In the end, I reverted to some obvious as day boolean logic of a == b && b == c
I’m glad I wrote a test for something so small, because this particular error in this particular place would have led to a substantial security hole.
Lesson learned: just because there’s a nicely named message that sounds right doesn’t mean it’s the message I want to send. Also, quit trying to be clever.
At some point in time Rails added a nicety to ActionMailer that I’ve really appreciated. The nicety I mention is that an html formatted email will be automatically translated into a plaintext email counterpart that is not perfect, but passable when iterating on a blossoming application.
As our applications mature we’re upping our efforts on accessibilty. Within that effort, the automatically generated plaintext emails are being replaced by artisinal plaintext emails.
We’re good about writing tests, but our tests broke when we moved from providing the single part to providing multiple parts.
Today I rel-learned how to get to the different parts of the email when they’re being provided explicitly.
-assert_includes email.body.encoded, "some expected text"
+assert_includes email.html_part.body, "some expected text"
+assert_includes email.text_part.body, "some expected text"
Thanks again Stackoverflow.
Ruby’s defined?
method is useful, but the syntax is a little surprising at first glance!
# These two are similar, but you call them different
defined? @whatever # call with the actual identifier
instance_variable_defined? :@whatever # call with a symbol of the identifier
defined?
returns a string of what identifier is. In this case, nil
or "instance-variable"
.
instance_variable_defined?
returns a bool.
When nil
is an acceptable memoized value, I often reach for a pattern of.
def whatever
return @whatever if instance_variable_defined? :@whatever
@whatever = some_expensive_computation
end
For tersness that communicates just as much, this could become
def whatever
return @whatever if defined? @whatever
@whatever = some_expensive_computation
end
Today I needed to re-raise an error in ruby, but change the error message slightly. It turns out this is baked right in to the use of raise
!
do
# something that raises
rescue => e
raise e, "This is my modified message"
end
import
statements can be picky When using ES2015. With the variety of Babel plugins and configurations it’s easy to have some technically invalid syntax that compiles just fine in that configuration.
// family.js
export default {
george: "Grandpa",
michael: "Dad",
maeby: "Cousin",
}
// uses_family.js
import { maeby } from "./family.js"
I don’t know what plugin I was relying on but previously this import statement worked. It turns out that destructuring off a default export is not actually a thing.
Option 1:
// family.js
export const george = "Grandpa"
export const michael = "Dad"
export const maeby = "Cousin"
export default { george, michael, maeby }
// uses_family.js
import { maeby } from "./family.js"
Option 2:
// family.js
export default {
george: "Grandpa",
michael: "Dad",
maeby: "Cousin",
}
// uses_family.js
import Family from "./family.js"
const { maeby } = Family
Rails will save associations by default. If you build an in-memory representation of a record that’s not intended to be saved with a call to update
you need to do one of two things.
has_one :other_thing autosave: false
.This default behavior manifested itself because I was doing something of the form:
class Thing
has_one :other_thing # 1. Use autosave: false
def optimistic_version_of_other_thing
OtherThing.new(thing: self) # 2. don't associate the record with self
end
end
thing = Thing.last
thing.optimistic_version_of_other # I don't want this persisted
thing.update(anything: "else")
I’m almost always wanting to add configuration hooks to Rails engines when I build them. Up to this point I’ve never taken the time to figure out the most succinct way to provide configuration hooks. It turns out that it’s much simpler than I even imagined.
module MyGem
class Engine < ::Rails::Engine
isolate_namespace MyGem
config.my_gem = ActiveSupport::OrderedOptions.new
config.my_gem.some_setting = true
end
end
That’s it! Setting config
directly in the class definition will expose the configuration in the consuming Rails application.
Today I re-learned about ActionController::TestCase
. It’s pretty common to send the request parameters in as the second argument. What I always forget is that the third and fourth parameters represent the session and the flash respectively.
test "something that depends on the session and the flash" do
post :create, { always: "money" }, { in: "the" }, { banana: "stand" }
assert_equal params[:always], "money"
assert_equal session[:in], "the"
refute_equal flash[:banana], "stand" # because the flash will have been flushed!
end
Multiple calls to ReactDOM.render
can be a super powerful tool. Given a state-ful component Counter
// Initial render into document.body
React.render(<Counter count=0 />, document.body)
// => { state: { count: 0 }, props: { count: 0 } }
// Something internal happens that changes state to 50
// => { state: { count: 50 }, props: { count: 0 } }
// Re-render without unmounting into document.body
React.render(<Counter count=100 />, document.body)
// => { state: { count: 50 }, props: { count: 100 } }
In many use-cases, flux
is introduced to distinguish between props and state. If props are changing on the server, this is a nice light-weight way re-render everything, while maintaining some client-side state. (Super helpful in rails in my usage)
While playing with webpack
in a Rails environment, there are still some variables I want to expose to the window. I came up with this 2-liner to treat exports from the top most bundle as global variables!
export { Whatever, You, Want }
Object.assign(window, exports)
When using elm make, the output is determined by the extension.
elm make Main.elm --output main.html # generates html
elm make Main.elm --output main.js # generates js
Put it in a Rakefile. Why incur the overhead of ruby my_script
, when you can just type rake
? It takes a little more time to write, but being able to return to a small folder and type rake -T
by convention makes you faster in the long run.
You are not allowed to complain about what you are not willing to confront. I saw that in a tweet a while ago, and it is a good word.
Prefixing methods that will change what is on output to the screen with render_
sounds verbose, but it has been helpful as I’ve started to use it more. Another React
convention that is informing other areas of development.
CORS is real. The part that really tripped me up, is the preflight OPTIONS request.
You can handle this options request in Rails with a nice routing constraint.
match '*', to: 'cors#handle', via: %i(options)
Then set your Access-Control-[Whatever]
headers accordingly, and you’re in business.
There are a lot of ways that payment can fail. Thankfully, Stripe provides ways to trigger almost every conceivable failure. And they put the credit card values that will trigger these failures into a handy doc.
It’s important to remember, some of these failures will occur when attempting to get a Stripe token. Others will fail when attempting to use the Stripe token.
When using Bugsnag within a Rails app, you must use the before_bugsnag_notify
macro within your ApplicationController
(or similar) to add custom info. I tried to be clever, using the Bugsnag.before_notify_callbacks
manually in an initializer. This didn’t work. My assumption is that Bugsnag.before_notify_callbacks.clear
is called somewhere internally in the Railtie
.
It pays to read the Bugsnag ruby docs.
In Rails’ Mailer Previews, you can append .text
to the URL to view the text version by default. Way better than reloading, and having to select text from the dropdown!
Rails.application.routes.url_helpers
can be used to access your URL helpers from anywhere.
In JavaScript, document.activeElement
gives you the active element. How did I never know this?
<<-SOMETHING.strip_heredoc
in Ruby, to strip the heredoc, and align to the current level of indentation. Doc
When working in Ruby, JSON.parse(payload, symbolize_names: true)
will automaticaly symbolize the names.
There is no magic for Rails’ enum
in fixtures. If you want to use the string value (which is the entire point of using the enum), you need to ERB it up. Something like
michael:
name: Michael Bluth
occupation: <%= Person.occupations[:actor] %> # because 'actor' won't do it
You can use %i[some symbols]
in ruby to generate [:some, :symbols]
You can use reorder on an ActiveRecordRelation to replace all existing order methods. It’s super useful when merging scopes that may have imported their own ordering that is no longer applicable.
Study the docs. As an example, there are so many methods on Enumerable that you can leverage to eliminate temporary variables. Don’t spend all your time reading the docs, but every once and a while it’s good to review what’s already built in the standard library that you don’t need to re-invent.
If you’re looking up a record by anything other than the primary_key
, don’t accept arbitrary arguments. Lazily looking up a record is great, but if you’re using something like
def destroy_do_dad(expecting_an_id_but_an_object_was_passed_in)
DoDad.where(foreign_system_id: expecting_an_id_but_an_object_was_passed_in).destroy
end
you have a huge vulnerability. #to_param
, will come into play, and you’re now potentially finding a completely arbitrary record and destroying it.
Let the database do all of the heavy lifting for counting your ActiveRecord objects.
Record.pluck(:owner_id).each_with_object(Hash.new(0)) { |id, counts|
counts[id] += 1
}
Sums up the number of records for a owner
in Ruby. The same can be achieved via ActiveRecord.
Record.group(:owner_id).count
When accessing the Rails flash
messages, use strings instead of symbols. I thought it was a HashWithIndifferentAccess…but it doesn’t appear to be.
Responding to http in Go on Dreamhost is pretty easy. The trick is to use FactCGI to serve it up.
I did this via a trivial conditional for my setup of developing on OSX, and deploying to Linux.
if runtime.GOOS == "linux" {
fcgi.Serve(nil, nil)
} else {
http.ListenAndServe(":2112", nil)
}
To cross-compile to Linux, you use the Go runtime flags.
GOOS=linux GOARCH=386 go build
I was reminded how evil DST is. It’s just the worst. Writing tests around it is the best. Just a reminder that 2am-3am on March 8, 2015 DOES NOT EXIST.
Some random commands from tinkering with Vagrant today:
dscacheutil -flushcache
# Flush the DNS cacheJavaScript Array’s map
function takes a optional second argument, of what to bind to this
.
Gulpfiles. I don’t know what I learned about them, but I helped a friend troubleshoot why gulp.watch()
and gulp-sass
combined to produce a Segmentation Fault 11. Something with libsass
, and rolling back the node-sass
version fixed it.
Computers.
Gourmet Service Objects is a post worth returning to from time to time. After slogging through some code to understand what it did, I wrote it into a service. The code wasn’t substantially different, but the fact that it had a name as first-class citizen instantly made it easier to understand.
Because my dudepal @jabronus gave me an SVG of my avatar, I started learning how to use SVG in the browser. I even made my avatar blink using CSS animations. Supes cool.
git log --pretty=oneline
gives you the one-line per a commit output.
git log --pretty=format:"%an"
gives you formatting on commits. All the interpolations available are listed in the man git-log
under “PRETTY FORMATS”.
attr_readonly
exists in Rails for making fields immutable. But we’re in Rails, so we don’t use big words like immutable, we use readonly. Caveat: you can still change the values in memory, which has other consequences around validations and any derived values.
Having opinions is more fun that trying to please everyone. Engage in helpful debate with reasonable people. Change your mind when presented with new data that should change your mind. Attack the problems together. Defend your teammates, not your opinions.
Don’t use Ruby’s or
, and
, or not
keywords. Just don’t. It’s not worth the hassle of slightly different behavior. Refer yourself to the Community driven ruby style guide often.
You can be incredibly productive, but feel unproductive. Fixing lots of small bugs leads to this. Keeping a list of everything completed such as Trello helps you remember that you’re making a lot of small progress when it feels like you’re not making any large progress.
There are many ways to write even the simplest statement.
# Allow lists.
# Which is most readable while being concise?
# 1
trusted = %w[approve reject].find { |i| i == untrusted }
# 2
trusted = (%w[approve reject] & [untrusted]).first
# 3
trusted = %w[approve reject].include?(untrusted) ? untrusted : nil
# 4
trusted = case untrusted; when *%w[approve reject]; untrusted; end
Aggressively eliminate state. After working with ReactJS for a bit, I am starting to see the merits of eliminating state. I’m even beginning to like methods prefixed with get
and set
. Eliminating state means eliminating side-effects.
Writing adolescent JS code seems to lead to better JS code. What I mean by adolescent code, is that it refuses to take responsibility. It lets somebody else own the state of the world. All it does is ask for values, and do something with them.
If you want to launch Vim from a Ruby script, use system 'vim'
. Backticks won’t work, because they want to consume STDOUT. exec
takes over the process, so you couldn’t do work afterwords. system
works.
Take breaks.
Lately, I’ve been taking breaks. Today I didn’t. And at end-of-day, the difference in energy level left for friends & family is substantially depleted.
Small changes are easier than big changes. Renaming things seems like a huge win, but when you’re renaming big things, small subtleties will emerge. These pitfalls are easier to see in others’ proposed changes than your own.
If you’re going to rename something, have a good purpose for it.
Look for the dumb solution. Sometimes refactoring isn’t needed yet. You don’t know enough about the problem to find the better solution, yet.
It’s important to know how to revert a commit, because sometimes you accidentally commit strait to master.
If you caught yourself before pushing upstream, you’re good. Just
git checkout -b temporary
git branch -D master
git checkout master
This assuming it automatically pulls master back down from upstream, which is my default setup.
If you did push upstream, you’ll basically want to create a commit that reverts the latest commit. Hopefully it’s only one commit.
git format-patch -1 HEAD
git apply [newly_created_patch_name] -R
You have to mull through a lot of terrible names, and iterate on terrible code to arrive at a consistent, reasonable API. Today I was building an ActiveSupport::Concern
whose purpose will be to cache attributes that are expensive to compute. The names of the methods changed a handful of times. And even now they may not be finalized.
I left the code for a few hours, and returned to it with a fresh set of eyes. The names were terrible. Their implied meaning was confusing. But because of this gap, I was able to see some of of the consistent shortcomings. I also saw patterns emerging, that lead to a more consistent API for the final iteration (of the day).
I started making a before_filter
that would redirect a request from a bot. After returning to the code, I decided it would be better to rescue_from SomeCustomError, with: :what_was_previously_a_before_filter
so that the code did not have to run on every single request. This probably amounts to minimal performance gains in terms of actual execution time, but I think it brought clarity to the code by having the happy path occur first.
Taking the time to organize your folders/files into something predictable needs to be done quickly when you’re working with branches of code. Every divergent branch means a delay in making it happen.
Reminded of a proposal I made long ago. For responsive design, start at one size, and head in one direction, using either min-width or max-width, but not both.
I spent time today moving some behavior of a model into a concern, specific to that model. Rather than putting it into app/models/concerns/person_pending_request_count
I put it into app/models/person/pending_request_count
. I liked this change, because it communicated that only Person should be using this. It’s not a general mixin, though it could easily become one. Then in the person class, I just included it with include Person::PendingRequestCount
.
Rails UJS’ ajax:success
and ajax:error
only apply to XHRs originating from a data-remote="true"
source. If you’d like them to apply to all XHRs in your page or application, you’re gonna have to wire that up.
In slim, you can use <
, >
or both after your tag to add leading or trailing whitespace, respectively.