Validate an XML document against an XSD schema with Ruby and Nokogiri
The code below shows a method #validate
which uses Nokogiri to validate an XML document against an XSD schema. It returns an array of Nokogiri::XML::SyntaxError objects.
require 'rubygems'
gem 'nokogiri'
require 'nokogiri'
def validate(document_path, schema_path, root_element)
schema = Nokogiri::XML::Schema(File.read(schema_path))
document = Nokogiri::XML(File.read(document_path))
schema.validate(document.xpath("//#{root_element}").to_s)
end
v...
Deploy and migrate with a single Capistrano command
Note that this sounds good but is not good at all when hooking tasks on cap deploy
(see this article). Make sure to hook your calls properly when using this.
To deploy an application and run all pending migrations before restarting it, you can use the following standard Capistrano task:
cap deploy:migrations
Little is known what happens when the deployment goes through, but a migration or a rake task aft...
Speed up file downloads with Rails, Apache and X-Sendfile
When you use the send_file
method to send a local file to the browser, you can save resources on the application server by setting the :x_sendfile
option to true
. This option is activated by default for Rails 3, so you need to understand this.
What this option does is not to send any data at all, but rather set the local file path as a new response header:
X-Sendfile: /opt/www/awesome-project/shared/downloads/image.png
When the response comes back from Rails to...
remove_index fails silently for non-existing indexes in Rails 2 migrations
When you try to remove a non-existing index using remove_index
, the migration will incorrectly pass without an error. The schema will not be changed, but the migration will be considered migrated.
Since this might be fixed in the future, you cannot mend your database by adding another migration on top of the faulty one. You should manually alter the database schema to the previous migration on all machines that migrated the faulty migration (inform your fellow developers), then delete the faulty migration from the repository.
OscarGodson/jKey - GitHub
jQuery plugin to register callback functions to keyboard shortkuts. Keyboard events in vanilla Javascripts are super-painful to work with, so hopefully this library can help.
Rails: When defining scopes with class methods, don't use `self`
Sometimes it is useful to define a named scope by implementing a static method with the scope's name on the scoped class. For instance, when a method should decide which existing scope should be the next link in the scope chain. Take this class for example:
class Meal < ActiveRecord::Base
named_scope :for_date, lambda { |date| :conditions => { :date => date }}
named_scope :with_meat, :conditions => { :meat => true }
named_scope :without_meat, :conditions => { :meat => false }
def self.suitable_for(user)
if user.vegetar...
MySQL: "LOAD DATA INFILE" says "file not found"
This might be due to AppArmor denying the MySQL server access to most of the filesystem. You can instead use
LOAD DATA LOCAL INFILE ...
to pipe data through the MySQL client, which can read everything the executing user can.
Properly sanitizing column names for MySQL
There are times when you need to send SQL to the database, like this:
def self.some_count(field)
field = connection.quote_column_name(field)
scoped(:select => "COUNT(DISTINCT #{field}) AS count")
end
Although the given variable is sanitized here, the MySQLAdapter's (and probably other adapters as well) method for this is insufficient as it only wraps backticks around it, not helping against injection:
Klass.some_count("id`); DELETE FROM users; -- ")
# Will result in this SQL which is valid but definitely undesi...
How to define constants with traits
When defining a trait using the Modularity gem, you must take extra steps to define constants to avoid caveats (like when defining subclasses through traits).
tl;dr
In traits, always define constants with explicit
self
.
If your trait defines a constant inside the as_trait
block, it will be bound to the trait module, not the class including the trait.
While this may seem unproblematic at first glance, it becomes a problem when including trai...
ETags with memcached
I love ETags, but there’s something that annoys me: most implementations revolve around pulling a record out of a data store and only “rendering” the response if it hasn’t been modified.
The problem with this approach is that request has already gone through most of your application stack–parsing params, authentication, authorization, a few database lookups–so ETags are only saving you render time and some bandwidth.
While working on a Sinatra-based JSON web service that gets very heavy traffic, I wanted to find a way to short-circuit...
Always show the page if there is an error in Cucumber
Are you adding a "Then show me the page
" and re-run Cucumber whenever there is a failing scenario? Don't be that guy!
Save time with the shiny new version of our cucumber_spinner gem. It comes with a Cucumber formatter that not only displays an awesome progress bar, and shows failing scenarios immediately, it will also open the current page in your browser whenever a scenario step fails.
After you installed the gem, use the formatter like this:
cucumber --format CucumberSpinner::Curiou...
Concurrency issues with find-as-you-type boxes
Find-as-you-type boxes are usually built by observing changes in a text field, and querying the server via AJAX for search results or suggestions when the field has changed.
A common problem with this implementation is that there is no guarantee that AJAX responses are evaluated in the same order as the original requests. The effect for the user is that the search results are flashing back and forth while the user is typing the query, and when the user has stopped typing the last results don't always match the final query.
Workarounds
----...
Speed up RSpec by deferring garbage collection
Update: This trick probably isn't very useful anymore in Ruby 2.x. The Ruby GC has improved a lot over the years.
Joe Van Dyk discovered that running the Ruby garbage collector only every X seconds can speed up your tests. I found that deferring garbage collection would speed up my RSpec examples by about 15%, but it probably depends on the nature of your tests. I also tried applying it to Cucumber f...
How to: Use git bisect to find bugs and regressions
Git allows you to do a binary search across commits to hunt down the commit that introduced a bug.
Given you are currently on your branch's HEAD that is not working as expected, an example workflow could be:
git bisect start # Start bisecting
git bisect bad # Tag the revision you are currently on (HEAD) as bad. You could also pass a commit's SHA1 like below:
git bisect good abcdef12345678 # Give the SHA1 of any commit that was working as it should
# shorthand:
git bisect start <bad ref> <good ref>
Git will fetch a comm...
Apache: Redirect all requests from one host to another
In order to redirect all requests from redirecting-host.com
to desired-host.com
while keeping path and query params unchanged, change your Apache VHost to something like this:
ServerName desired-host.com
ServerAlias redirecting-host.com
RewriteEngine On
RewriteCond %{HTTP_HOST} !^desired-host.com$
RewriteRule ^.*$ http://desired-host.com%{REQUEST_URI} [R=301,L]
Take care to keep all those ^
, $
and !
as seen in the example.
Export CSV from MySQL directly
If you need to export data from MySQL to a CSV, you can profit from really fast built-in methods.
This query writes the data to /tmp/geodb_coodinates.csv. And it's fast: Query OK, 337925 rows affected (0.86 sec)
SELECT * INTO OUTFILE '/tmp/geodb_coordinates.csv' FIELDS TERMINATED BY ',' ENCLOSED BY '"' ESCAPED BY '\\' LINES TERMINATED BY '\n' FROM geodb_coordinates;
Reset MySQL query cache
To clear the query cache in your MySQL database manually, e.g. for database profiling, execute the following command in your MySQL console:
RESET QUERY CACHE;
Apply a new callback to existing records
So you added a new callback to your model that (e.g.) caches some data when it is saved. Now you need to run that callback for the 10000 existing records in the production database. You have two options here:
- Write a clever migration, possibly by embedding the model into the migration script.
- Open the Rails console after deployment and re-save every single record. You should probably add two chores to your issue tracker so you won't forget t...
Check if a field or button is disabled with Cucumber
Using this step definition you can check if any form field (text field, checkbox, etc) or button is disabled:
Then the "Name" field should be disabled
And the "Save" button should be disabled
But the "Locked" field should not be disabled
Capybara
This step part of Spreewald.
Webrat
Then /^"([^\"]*)" should( not)? be disabled$/ do |label, negate|
attributes = field_labeled(label).element.attributes.keys
attributes.send(negate ? :should_not : :should...
Preloaded associations are filtered by conditions on the same table
When you eagerly load an association list using the .include
option, and at the same time have a .where
on an included table, two things happen:
- Rails tries to load all involved records in a huge single query spanning multiple database tables.
- The preloaded association list is filtered by the
where
condition, even though you only wanted to use thewhere
condition to filter the containing model.
The second case's behavior is mostly unexpected, because pre-loaded associations usually don't care about the circumstances under whi...
Use the contents of a WordPress database in your Rails app
These two models can be used to access the posts and associated comments of a WordPress database.
Git: Changing commit messages
To change the commit message of the latest (unpushed, unmerged) commit, you can use
git commit --amend
To change the commit message of an earlier (unpushed, unmerged) commit [COMMIT], you can do
git rebase -i COMMIT~
For a current version of git, you can simply mark the line with "reword", and git will ask you later for the new message.
For older versions:
- mark the line with
edit
- save the file
- do a
git commit --amend
when rebasing stops at the relevant commit git rebase --continue
Hints for debugging MySQL InnoDB deadlocks
Deadlocks only occur if two transactions in separate threads compete for the same rows in the database. They usually (but not necessarily) only happen when trying to update or otherwise lock several rows in different order.
Solving deadlocks is potentially complicated, so here are a few pointers:
- MySQL should always detect the deadlock right when it happens, and will throw an error to one of the offending threads. This error states the SQL statement that this thread was currently waiting for, and that tried to acquire one of the competin...
Git: Amending older commits
Lets say you need to make a change to a commit OLD_COMMIT
, but this is not the most recent. If you have neither pushed nor merged it, you can do this:
- Make a new commit now, with a message like "fix".
- Do a
git rebase -i OLD_COMMIT~
- In the editor window that opened, move the "fix" commit directly after the one you want to amend (so it should be the second from the top), and mark it as "fixup". Save the file.
- If there are conflicts, solve them, add them, and do
git rebase --continue