Taming icon fonts for use in Rails views
Icon fonts like Font Awesome are infinitely scalable, look great on high-DPI displays and will give your app a modern look.
However, icon fonts can be very awkward to use compared to raster icons. Elements are given icons by giving them a special class like icon-plus
or icon-home
:
<span class="icon-plus">Create</span>
The icon font's stylesheet will then recognize this class and insert the icon as the element's :before
style.
In practic...
Cucumber: Wait for any requests to finish before moving on to the next scenario
Background
Generally, Selenium tests use the browser to interact with the page. If it's unavailable, a timeout error is thrown.
Now, consider a scenario like this:
@javascript
Scenario: Receive an e-mail after clicking the fancy link
When I follow "fancy link"
Then I should have an e-mail with the subject "Hello"
When the last step in the scenario passes, you are done. Right? Wrong.
Why it's not enough
What if clicking our "fancy link" above sends the e-mail that we expect, but it also does stuff on the server...
Ruby: Extract the hostname from a URL
url = 'http://www.foocorp.com/foo/bar'
URI.parse(url).host
# => www.foocorp.com
Note that this will raise an error if the given argument is not a URL.
If you need the host's full URL without path, query, fragment etc., use URI.join
with a clever twist:
url = 'http://www.foocorp.com:33546/foo/bar?query=foobar#hash'
URI.join url, '/'
# => http://www.foocorp.com:33546/
Advice: Reduce scopes with joins to simple IN-queries
In theory you can take any scope and extend it with additional joins or conditions. We call this chaining scopes.
In practice chaining becomes problematic when scope chains grow more complex. In particular having JOINs
in your scope will reduce the scope's ability to be chained with additional JOINs
without crashes or side effects. This is because ActiveRecord doesn't really "understand" your scope chain, it only mashes together strings that mostly happen to look like a MySQL query in the end.
**I don't generally advice against u...
ActiveModel::Errors inherits from hash and behaves unexpectedly
ActiveModel::Errors
is used to handle validation errors on Rails objects. If you inspect an instance, it feels like a hash (to be more precise, it inherits from Hash):
errors = ActiveModel::Errors.new(Object.new)
=> {}
>>
?> errors.add(:base, "foo")
=> ["foo"]
>> errors.add(:base, "bar")
=> ["foo", "bar"]
>>
?> errors
=> {:base=>["foo", "bar"]}
If you need to hack anything with these errors, beware that it behaves in a special way. If you iterate over the errors it will decompose arrays.
For ...
Manually requiring your application's models will lead to trouble
In a nutshell:
If you require your Rails models manually, pay attention to the path you use. Unless you have to, don't do it at all.
Background
Consider these classes:
# app/models/user.rb
class User < ActiveRecord::Base
validate :magic
def magic
errors.add_to_base('failed') if bad_things?
end
end
^
# app/models/foo.rb
require 'user'
class Foo
# something happens here
end
Now, when your environment is booted, Rails will automatically load your models, like User
...
Automatically strip all string fields of an ActiveRecord
If your application has forms to edit string fields, you probably want to strip the entered values (remove whitespace from beginning and end). The reason is that your users will copy + paste values from unholy places (websites, Microsoft Office) and end up having trailing whitespace in most of their records.
Because browsers ignore whitespace, no one will usually notice this until you get the weirdest bug reports (e.g. two seemingly equal records are not, or multiple records for "unique" values).
Use the attached trait in your model to hav...
7 Ways to Decompose Fat ActiveRecord Models - Code Climate Blog
“Fat models” cause maintenance issues in large apps. Only incrementally better than cluttering controllers with domain logic, they usually represent a failure to apply the Single Responsibility Principle (SRP). “Anything related to what a user does” is not a single responsibility.
Early on, SRP is easier to apply. ActiveRecord classes handle persistence, associations and not much else. But bit-by-bit, they grow. Objects that are inherently responsible for persistence become the de facto owner of all business logic as well. And a year or tw...
Howto transfer a single mysql table between several deployment stages
Example task: Multiply the table holidays
between several stages.
-
Open two terminals:
shell-for stage_1 shell-for stage_2
-
Get the stage1 and stage2 MySQL credentials:
cat /opt/www/the_stage.host.tld/current/config/database.yml cat config/database.yml # should do it
-
Dump the table to a path reachable by the stage2 user (e.g. home):
mysqldump -h mysql1 -u stage_1_user -p stage_1_database table_name > ~/table_name_dump.mysql # Select certain records using --where "some_id > 666"
(-...
Unsaved record disappears when assigning to an association
If this happens to you:
user.avatar = Avatar.new
user.avatar # => nil
(where avatar
is a belongs_to
), you probably declared your association incorrectly.
Always do
class User < ActiveRecord::Base
belongs_to :avatar
end
and never
class User < ActiveRecord::Base
belongs_to 'avatar'
end
Spreewald: Old-school cucumber steps, freshly pickled
Cucumber_rails' old-school web-steps have been deprecated for a while, urging developers to write high-level step definitions that directly use Capybara or Webrat.
We think that's a bit drastic. More high-level steps are good, but ticking the odd check box with a general step is not always bad.
So we took the old web steps, improved them a bit, added some other favorites of ours (steps for emails, tables, [time travelling](/ma...
How to not leave trailing whitespace (using your editor or Git)
There is no reason to leave trailing whitespace characters in your project's files, so don't add any.
A git diff --check
will tell you if there are any and you should not commit when you see them. So go ahead and switch your editor/IDE to automatically remove them for you.
Below are a few instructions on how to get them removed by your favorite IDE or editor.
Note that except for RubyMine, the following changes will remove trailing white-space on all lines, not only those that you changed.
While this should not be a problem if your proje...
Using before(:context) / before(:all) in RSpec will cause you lots of trouble unless you know what you are doing
TL;DR Avoid before(:context)
(formerly before(:all)
), use before(:example)
(formerly before(:each)
) instead.
If you do use before(:context)
, you need to know what you are doing and take care of any cleanup yourself.
Why?
Understand this:
-
before(:context)
is run when thecontext
/describe
block begins, -
before(:context)
is run outside of transactions, so data created here will bleed into other specs -
before(:example)
is run before each spec inside it,
Generally, you'll want a clean setup for each s...
Git basics: checkout vs. reset
Today I got a better understanding of how git works, in particular what git checkout
and git reset
do.
Git basics
- A commit holds a certain state of a directory and a pointer to its antecedent commit.
- A commit is identified by a so-called ref looking something like
7153617ff70e716e229a823cdd205ebb13fa314d
. - HEAD is a pointer that is always pointing at the commit you are currently working on. Usually, it is pointing to a branch which is pointing to that commit.
- Branches are nothing but pointers to commits. Y...
Distribute files from a private bucket on AWS S3
Given you store files on Amazon S3 and you need to stream those files out to people while you don't want them to be able to distribute the content simply by sharing the S3 URL.
You could either mark the bucket as private and fetch the appropriate files from S3 to your application server and stream them to the client finally. While this is possible, I'd recommend to use what AWS calls "Query String Authentication".
If you're using Paperclip you can chose between two sto...
Highlight current navigation item with Staticmatic
StaticMatic is a nice tool to build simple static websites.
In case you want to have some nifty styles on the navigation item that is currently active, you can use this:
=link 'Aktuelles', :class => (current_page =~ /aktuelles/) ? 'current' : 'default'
Keep in mind that current_page
gives you the full relative path of your page. raise
current_path in case you're not sure.
I know there is an navigation helper out there. I did not use it and also did not want to migrate.
See which MySQL database is currently in use
When you work in the MySQL console and you want to see which database is used, type:
SELECT database();
The result you see is the database you would activate with
USE database_name;
Paperclip: Move attachements from local storage to AWS S3
We frequently use the handy Paperclip Gem to manage file attachments.
If you need to move the files from local storage (i.e., your servers' harddisk) to Amazon S3, you can simply change settings for Paperclip to use the S3 storage adapter and use this script to migrate to S3. Put the snippet into a chore if you don't want to run that in the console.
YOUR_LOCAL_STORAGE_MODEL_DIRECTORY should be something like 'storage/your_model'.
Dir.glob(YOUR_LOCAL_STORAGE_MODEL_DIRECTORY**/*).each do |path|...
Boolean fields in migrations
If you want to update some records with boolean fields in a migration, always remember to set your values with field=#{quoted_true}
and field=#{quoted_false}
. The Rails methods quoted_false
and quoted_true
return the correct boolean representations for your database.
How to test print stylesheets with Cucumber and Capybara
A print stylesheet is easy to create. Choose a font suited for paper, hide some elements, done. Unfortunately print stylesheets often break as the application is developed further, because they are quickly forgotten and nobody bothers to check if their change breaks the print stylesheet.
This card describes how to write a simple Cucumber feature that tests some aspects of a print stylesheets. This way, the requirement of having a print stylesheet is manifested in your tests and cannot be inadvertedly removed from the code. Note that you can...
Reset mysql root password
This article describes how to reset MySQL's or MariaDB's root password on your workstation. It's meant for local development purposes only, don't do this in production. This article will also help you if you have a fairly recent MariaDB version that uses authentication based on linux users instead of passwords for the root user and you prefer using a password for root.
Solution
Step 1 is getting a root mysql shell that allows us to change user credentials. We need to stop the mysql
daemon first and re-start it without authorization c...
Scoping a sunspot solr search by text using a string field
Assuming the following sunspot setup of the post class:
class Post < ActiveRecord::Base
searchable do
text :title
string :state
integer :category_ids
end
end
In Sunspot you can scope your search via the with
method. It allows you to do stuff like:
Post.search {
fulltext "your query", :fields => :title
with(:category_ids).any_of([1,2,3,4,5])
}
If you want to scope your search based on a text field, you have to add another field of the type string
(such as the state fi...
Accept nested attributes for a record that is not an association
Note: Instead of using the method in this card, you probably want to use ActiveType's nested attributes which is a much more refined way of doing this.
The attached Modularity trait allows you to accept nested attributes for a record that is not an association, e.g.:
class Site < ActiveRecord::Base
def home_page
@home_page ||= Page.find_by_name('home')
end
does 'a...
Git: When committing, check the diff
When committing, you should always check the diff of your changes so you don't include any leftovers or irrelevant/bad changes. Any time spent on that is well invested as it saves you rejected merge requests or any mess you need to clean up later.
While you can just use git diff
or git diff --cached
(to diff staged changes), you can also have Git include the changes as a comment below the commit message:
git commit -v
That will open up the usual commit "file" in your preferred text editor, but it will include a diff below the s...