travisliu/traim: Resource-oriented microframework for RESTful APIs
Use Traim to build a RESTful API for your ActiveRecord models with very little code.
Traim assumes your API resources will map 1:1 to your ActiveRecord models and database tables. This assumption usually falls apart after a few months into a project, so be ready to replace your Traim API with something more expressive afterwards.
Traim outputs a Rack application which you can either serve standalone or mount into your Rails app.
Deleting stale Paperclip attachment styles from the server
Sometimes you add Paperclip image styles, sometimes you remove some. In order to only keep the files you actually need, you should remove stale Paperclip styles from your server.
This script has been used in production successfully. Use at your own risk.
# Config #######################################################################
delete_styles = [:gallery, :thumbnail, :whatever]
scope = YourModel # A scope on the class with #has_attached_file
attachment_name = :image # First argument of #has_attached_file
noop ...
IRB: last return value
In the ruby shell (IRB) and rails console the return value of the previous command is saved in _ (underscore). This might come in handy if you forgot to save the value to a variable and further want to use it.
Example:
irb(main):001:0> 1 + 2
=> 3
irb(main):002:0> _
=> 3
irb(main):003:0> a = _
=> 3
RSpec's hash_including matcher does not support nesting
You can not use the hash_including argument matcher with a nested hash:
describe 'user' do
let(:user) { {id: 1, name: 'Foo', thread: {id: 1, title: 'Bar'} }
it do
expect(user).to match(
hash_including(
id: 1, thread: {id: 1}
)
)
end
end
The example will fail and returns a not very helpful error message:
expected {:id => 1, :name => "Foo", :thread => {:id => 1, :title => "Bar"}} to...
ActiveRecord::RecordNotFound errors allow you to query the :name and :id of the model that could not be found
ActiveRecord::RecordNotFound errors provide quite meaningful error messages that can provide some insight on application details. Consider the following:
ActiveRecord::RecordNotFound: Couldn't find Organisation::Membership with 'id'=12 [WHERE "organisation_memberships"."user_id" = 1]
You should probably not simply render those error messages to the user directly. Instead you you might want to re-raise your own errors. ActiveRecord::RecordNotFound provides you with methods :model and :id where you can get information about w...
Ruby: define a class with Struct.new
This card will show you a cool way to define a class using Struct.new.
A common usecase for Structs are temporary data structures which just hold state and don't provide behaviour. In many cases you could use a simple hash as a data structure instead. However, a Struct provides you with a nice constructor, attribute accessors and complains if you try to access undefined attributes. Structs are easy to compare (by attributes). A struct gives meaning to the data.
Disclaimer
Structs are great...
Speed up better_errors
If you use the Better Errors gem, you will sometimes notice that it can be very slow. This is because it sometimes renders a huge amount of data that will actually be hard to render for your browser.
You can significantly improve performance by adding this to config/initializers/better_errors:
if defined?(BetterErrors) && Rails.env.development?
module BetterErrorsHugeInspectWarning
def inspect_value(obj)
inspected = obj.inspect
if inspected.size > 20_000
inspec...
Shoulda Matchers: how to test conditional validations
Shoulda Matchers don't provide canditional validations (validations with if: option). Here is how to write tests for the condition:
Class:
class Employee < ActiveRecored::Base
validates :office, presence: true, if: manager?
def manager?
...
end
end
Test:
describe Employee do
describe '#office' do
context 'is a manager' do
before { allow(subject).to receive(:manager?).and_return(true) }
it { is_expected.to validate_presence_o...
MySQL 5.7.5 enables `ONLY_FULL_GROUP_BY` mode per default
When using GROUP BY, MySQL now complains if the SELECT includes columns which are not part of the GROUP BY.
Reason:
There could be multiple values for those columns per group but only one value can be picked for the results.
The default behaviour of MySQL prior to version 5.7 will not complain and arbitrarily choose a value. But this leads to non-deterministic results. So MySQL now has enabled the only_full_group_by setting by default to prevent this.
In Rails this could lead to some trouble, because scopes do not have sp...
Rails: How to write custom email interceptors
Nowadays it is fairly easy to intercept and modify mails globally before they are sent. All you have to do is register an interceptor class which responds to .delivering_email(message). This card will show you two common use cases.
Subject prefix:
Usually you want to prefix the subject line of emails with the current environment (except production) so you can differentiate between production mails and mails from other environments. Of course a...
Working with or without time zones in Rails applications
Rails supports time zones, but there are several pitfalls. Most importantly because Time.now and Time.current are completely different things and code from gems might use one or the other.
Especially configuring an application that cares only about one time zone is a bit tricky.
The following was tested on Rails 5.1 but should apply to Rails 4.2 as well.
Using only local time
Your life will be easier if your application does not need to support time zones. Disable them like this:
config.time_zone = 'Berlin' # Your local ...
Webmock's hash_including doesn't parse query values to string
Webmocks hash_including is similar to RSpec::Mocks::ArgumentMatchers#hash_including. Be aware that hash_including (webmock v3.0.1) doesn't parse integer values to String.
Without hash including you would say:
uri = URI('http://example.com/?foo=1&bar=2')
stub_request(:get, 'example.com').with(query: {foo: 1, bar: 2})
Net::HTTP.get(uri) # ===> Success
If you only want to check if foo is present you can use hash_including:
uri = URI('http://example.com/?foo=1&bar=2')
stub_request(:get, 'example.com').with(query: hash_i...
HTTP/2 push is tougher than I thought - JakeArchibald.com
TLDR: Browser implementations of HTTP/2 push are horrible. You might end up with worse performance than without pushing. However, the article includes a great explanation of how HTTP/2 push are supposed to integrate with browser APIs.
Quickly printing data in columns on your Ruby console
Dump this method into your Ruby console to quickly print data in columns. This is helpful for e.g. comparing attributes of a set of Rails records.
def tp(objects, *method_names)
terminal_width = `tput cols`.to_i
cols = objects.count + 1 # Label column
col_width = (terminal_width / cols) - 1 # Column spacing
Array(method_names).map do |method_name|
cells = objects.map{ |o| o.send(method_name).inspect }
cells.unshift(method_name)
puts cells.map{ |cell| cell.to_s.ljust(col_width) }.join ' '
end
nil
end
Usag...
Using ActiveRecord with threads might use more database connections than you think
Database connections are not thread-safe. That's why ActiveRecord uses a separate database connection for each thread.
For instance, the following code uses 3 database connections:
3.times do
Thread.new do
User.first # first database access makes a new connection
end
end
These three connections will remain connected to the database server after the threads terminate. This only affects threads that use ActiveRecord.
You can rely on Rails' various clean-up mechanisms to release connections, as outlined below. This may...
Storing trees in databases
This card compares patterns to store trees in a relation database like MySQL or PostgreSQL. Implementation examples are for the ActiveRecord ORM used with Ruby on Rails, but the techniques can be implemented in any language or framework.
We will be using this example tree (from the acts_as_nested_set docs):
root
|
+-- Child 1
| |
| +-- Child 1.1
| |
| +-- Child 1.2
|
+-- ...
How to use Parallel to speed up building the same html partial multiple times (for different data)
The parallel-gem is quite easy to use and can speed up rendering time if you want to render the same partial multiple times (e.g. for rendering long lists of things).
Parallel supports execution using forked processes (the default), threads (mind the GVL) and Ractors (some limitations for data sharing).
If your parallelized code talks to the database, you should [ensure not to leak database connections](https://makandracards.com/makandra/45360-using-activerecord-with-threads-will-leak-database-connect...
Rendering 404s for missing images via Rails routes
When you load a dump for development, records may reference images that are not available on your machine.
Requests to those images may end up on your application, e.g. if a catch-all route is defined that leads to a controller doing some heavy lifting. On pages with lots of missing images, this slows down development response times.
You can fix that by defining a Rails route like this:
if Rails.env.development?
scope format: true, constraints: { format: /jpg|png|gif/ } do
get '/*anything', to: proc { [404, {}, ['']] }
...
How to disable Chrome's save password bubble for Selenium tests
When filling out forms in Selenium tests, Chrome shows the (usual) bubble, asking to store those credentials.
While the bubble does not interfere with tests, it is annoying when debugging tests. Here are two ways to disable it:
Option 1: prefs
You can set profile preferences to disable the password manager like so:
prefs = {
'credentials_enable_service' => false,
'profile.password_manager_enabled' => false
}
Capybara::Selenium::Driver.new(app, browser: :chrome, prefs: prefs)
Sadly, there are no command line s...
Rails: Default generators
This is a visualization of the files that will be generated by some useful rails generators. Invoke a generator from command line via rails generate GENERATOR [args] [options]. List all generators (including rails generators) with rails g -h.
| generator | model | migration | controller | entry in routes.rb
|
views | tests |
|---|---|---|---|---|---|---|
| scaffold | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ |
| resource | ✔ | ✔ | ✔ ... |
ActiveRuby
Looks like ActiveState is trying to market a new Ruby distribution for Enterprises:
ActiveRuby Enterprise Edition is designed for businesses with large Ruby deployments in essential, mission-critical applications that, when down, could cost your business in lost revenue and a damaged reputation. Deploy Ruby with confidence knowing you're using the most secure, enterprise-grade builds for the platforms that power your business. You'll get priority access to our Ruby experts for technical support and best prac...
VCR: Inspecting a request
Using VCR to record communication with remote APIs is a great way to stub requests in tests. However, you may still want to look at the request data like the payload your application sent.
Using WebMock, this is simple: Make your request (which will record/play a VCR cassette), then ask WebMock about it:
expect(WebMock).to have_requested(:post, 'http://example.com').with(body: 'yolo')
Easy peasy.
Related cards
Thinkpad: Disable Bluetooth on start-up
Add the following to /etc/rc.local:
(sleep 3 && echo disable > /proc/acpi/ibm/bluetooth)&
Bluetooth icon will be active for a few seconds, then turn gray.
Some useful vim settings
Below is a list of some VIM settings I find useful. You can add them to your .vimrc.
source $VIMRUNTIME/mswin.vim " adds Ctrl-X, Ctrl-C, Ctrl-V; block visual mode is now Ctrl-Q
behave mswin
set autowriteall " autosave all files when a buffer is closed
set backupdir=~/.temp " dont pollute local directory with swap file, backup files etc
set dir=~/.temp
set undofile " enable persistent undo
set undodir=~/.temp
set encoding=utf-8
...