Assert_tag With Two Siblings In Rails

I was recently dealing with a tricky problem while writing some rails tests.

I was writing assert_tags against xml returned by a rails web service in order to test that the xml contained specific values.

Here is a sample of the XML:

<elements>
  <element>
    <name>rod</name>
    <surname>hilton</surname>
    <value>123</value>
  </element>
  <element>
    <name>rod</name>
    <surname>smith</surname>
    <value>456</value>
  </element>
  <element>
    <name>granny</name>
    <surname>smith</surname>
    <value>789</value>
  </element>
</elements>

I want to write three assertions. If I write this in my test, it will work as expected:

assert_tag :tag=>"value", :content=>"789",
           :sibling=>{:tag=>"name", :content=>"granny"}

Basically what I'm doing is looking for a value element with the content of 789, and it has to have a sibling of a name element with the content "granny", which assures it will select the last "element" for the value.

The problem is, how do I write a test for the first xml element? If I look for a sibling with name "rod", it's possible that I'd select the second element. If look for a sibling with the surname "smith", it's possible that I'd select granny again. I need to be able to select the tag with TWO siblings.

The documentation is not straightforward about how to do this, but I figured out a method that works.

Essentially, the :sibling hash element takes the same kind of hash that assert_tag takes. Meaning, you can pass anything into :sibling that you would pass to assert_tag to begin with - including another sibling!

assert_tag :tag=>"value", :content=>"123",
           :sibling=>{
             :tag=>"name", :content=>"rod",
             :sibling=>{
               :tag=>"surname", :content=>"hilton"
             }
           }

Pretty insane, but I wasn't able to figure out a better way. I was hoping to pass an array of hashes to :sibling, but that didn't work as I had hoped.

If anyone has a better way than this, feel free to leave a comment. Otherwise, this seems to be a relatively readable way of selecting tags with 2 (or more) siblings in assertions.

Setting JAVA_HOME in a Batch File

Recently at work I had a bizarre problem to deal with. Essentially, we are distributing an application that uses JRuby, and we were encountering a problem whenever people would use our application in Windows if they installed Java in a specific way.

A lot of Windows users install Java not by putting the bits on disk and setting JAVA_HOME, but by adding java.exe to their path. When done this way, Java works in the sense that you can type "java" in a command prompt and have it understand what that means. You can compile java from command line and run it with no problem.

The problem we experienced was that JRuby, in windows, specifically looks to see if JAVA_HOME is set. If it is not set, the JRuby executable bails. I submitted a patch to JRuby to fix this behavior, but we could not rely on that solution until it was integrated.

What we are doing now is, in the batch file that we have that calls our application, we look to see if JAVA_HOME is set and, if it is not, step through the PATH looking for java.exe. We then set JAVA_HOME based on the location. As a result, by the time the JRuby script runs, JAVA_HOME has been set.

This is actually a handy trick to look for anything in the path in a Windows batch file.

Here's the code:

if not "%JAVA_HOME%" == "" goto javaHomeAlreadySet
for %%P in (%PATH%) do if exist %%P\java.exe set JAVA_HOME=%%P..\
:javaHomeAlreadySet

Holy Shit, I’ve Been Hacked

Apparently there is some wordpress vulnerability that allows someone to replace my header file with a whole bunch of viagra links. Awesome.

Anyway, it actually overwrote the file on the server, so my design is all busted and I don't have it backed up in any way.

I'll be upgrading wordpress and fixing my site theme. This may take some time. Bear with me.

No, this is not an April fools thing. I actually got haxx0red, for realz. :/

Update: Alright, I've upgraded wordpress and removed the viagra links. It appears that someone was able to override my footer and header.php files for my theme. To an extent, I'm not terribly surprised, as those files are set world writable so that wordpress can write to them, allowing me to edit from the admin console.

This whole thing could have been much worse. The hack left my database untouched, all of my blog posts look the way they are supposed to. All it did was modify the files to my theme.

That said, because it so thoroughly destroyed my theme and I didn't back my theme up on my local machine (it's just a blog), I have set the site to use the default ugly wordpress theme until I can work up another one. It's just as well, I was sick of the old one anyway.

Extra Update: I just wanted to share the comment that informed me something was wrong with my site. It's humorous. These were both anonymous:

Real quick…I want an explanation for what the hell happened to your site or I’m reporting it to your hosting company and to Google. Two days ago I found this post and this site through Silicon Alley Insider and bookmarked it because I liked the blog design and wanted to work on something around it. I come back tonight and obviously the CSS file is gone. I clicked “view source” and not only is there no CSS file, there is no document head, no robots file, but there are about a thousand links to spam drug sites embedded in the source? You really don’t want me screencapping and posting this here and there, and you definitely don’t even want me to get started with Google, of all companies, reporting your ass if this isn’t a case of a your website being hacked.

Then later, same person:

You can hold my comments for moderation, I don’t care. I think you’re fucked either way. Looks like this site is owned and operated by the (fictitious?) Rod Hilton, whose own website is on a Google server. Try explaining that and all the spam links served to this site dynamically, viewable in the page source, before I get going on explaining it for you. You definitely don’t need to show my comments here to bury yourself in a world of shit.

Jesus, what a spazz. Well, thanks for letting me know my site was hacked, even if you did so by being a crazy person.

How To Play Peter Rottentail

I hate Easter. In fact, with the exception of Halloween, I hate pretty much all holidays. I hate easter in particular though. Growing up, Christmas was the present holiday and Easter was the candy holiday, and I couldn't care less about most candy (at least when compared to presents). Easter was a no big deal kind of day for me. It meant I had to wear khakis to church, but that's about it.

However, my fiancee comes from a Catholic family, and Easter was a very big deal to them. They hid eggs, they hid baskets, they got presents, the whole deal. So as she and I integrate our lives together, doing something for easter is important, but I don't particularly like any of the egg-hiding mumbo jumbo. At least I didn't, until this year.

I have devised a system that makes Easter fun. It is a game that I have dubbed 'Peter Rottentail'.

Peter Rottentail essentially turns innocent and lame Easter festivities into seedy gambling events. I will detail the rules of how to play Peter Rottentail in this post. This is a great game to play for people without any kids who want to do something for Easter.

Continue reading ‘How To Play Peter Rottentail’ »

Using Multiple Versions Of Rails

It's quite easy to have multiple versions of rails installed as gems when working with ruby on rails. Quite frequently, you will be working on a project that uses an older version of rails than one on your machine, and all you have to do to get the correct version is:

gem install -v 1.2.3 rails --include-dependencies

Multiple versions of rails can exist independently on your machine without much of a problem. Since your individual rails projects store the version number they expect, and your projects don't tend to depend on each other, you can have hundreds of different rails versions installed and never notice. Mostly.

If, however, you wish to start a NEW project, when you run

rails projectname

It will use the most recent version of rails. But what if, for some reason, you have rails 2.0.1 and rails 1.2.6 on your machine, and wish to generate a rails 1.2.6 application? This came up because I'm trying to teach a friend rails, and the book he has is for rails 1.2, meaning that if he uses 2.0 all of the scaffolding code (as well as other bits) from the book are incorrect. At the same time, the application he and I are working on together uses rails 2.0, so he needs both versions on his machine.

This solution works in linux (haven't tried windows):

rails _1.2.6_ projectname

I didn't see any documentation about this anywhere. In fact, I found it by cracking open the actual 'rails' script in /usr/bin and noticing that it did a regex match for a parameter that started and ended with underscores, then interpreted that as the version.

In any case, this allows you to happily generate a new rails app using an old version of rails. Nothing quite like discovering an undocumented feature by reading the source code.

My First Caucus: The Tale Of The Reluctant Delegate

This past Super Tuesday, I participated in the Caucus in Colorado. This was my first experience doing anything like this. I vote in every election, but typically I have absentee ballots mailed to me in order to vote. I'm normally registered as an independent, so I can't do much more than vote in the election itself anyway. This year, however, was quite different. I actually got involved.

Getting involved, in short, sucked. This is my story of why. Normally I would put pictures into a post this long, but I didn't realize until the Caucus was over that it was going to be such a ridiculous experience as to warrant a blog post, so I didn't take any pictures. Good for you if you manage to get through all of this anyway.

Background

For the first time, hearing a politician speak actually got me excited. Normally I view voting as a choice between the lesser of two evils, but for the first time a candidate was talking about things that really mattered to me. Ron Paul talked not only about how we shouldn't be in Iraq, but about how our foreign policy is actually making us less safe, from a practical standpoint. Ron Paul talked about how the executive branch has gotten too powerful, and it needed to be trimmed back. He talked about empowering states, and he talked about decreasing the overall power of the federal government. These were all things that were important to me, and hearing a person actually running for president talking about those things got me excited enough that I registered as a republican so I could support him.

Now, that was many months ago. Since that time, my support for Ron Paul has decreased. Not dramatically, but I'm nowhere near as enthusiastic as I was once. While the idea of adopting the gold standard for currency and abolishing the IRS both appeal to me, they both seem too extreme to do anything other than hurt the country. Ron Paul's stances on technology greatly irritate me - particularly that people trumpet it as a good thing (many clamor that "he voted against regulating the internet" like it's a reason to vote for him. I don't think people understand that was a vote AGAINST Net Neutrality). He has pushed numerous pieces of legislation forward that seem to contradict his world view of limited federal government, most notably bills that have to do with his personal religious beliefs. He is pro-life (I'm not). He trusts the free market a bit too much for my personal taste (a common problem with Libertarian candidates, who would seemingly like to remove things like the FDA). Despite all of these reasons (which would normally make a candidate lose my support), he still trumpets more than any other candidate how important our civil liberties are. In a "post 9/11 world", it's rare to see a politician actually espouse the position that our liberties are more important than our safety, and Ron Paul still does - vehemently. The short of all of this is that, by the time the caucus rolled around I was still a big Ron Paul Fan, but I was no longer a Ron Paul Zealot.

At the same time, Barack Obama was talking about a lot of things that mattered to me as well: the war, civil liberties, the war on drugs, and he also got bonus points for his views on technology. Between Obama and Ron Paul, I would have a hard decision to make. Yes, the two disagree on a LOT, but that doesn't mean it's impossible for me to support either one. Support for Paul would only exclude support for Obama if I supported ALL of Ron Paul's policies, which I do not. Their overlap is significant, and they both appeal to different aspects of what is important to me.

By February 5th, the republicans still in the running were Mike Huckabee, Ron Paul, Mitt Romney and John McCain. Of those four, Ron Paul is, in my opinion, the best candidate by miles. There was no need, at that point, to consider the fact that I was growing increasingly partial to Obama, since Obama wasn't running as a republican. On February 5th, I had two options: one, I could stay home and not participate at all on the grounds that I might not vote for Ron Paul if he were running against Obama, or two, I could recognize that Paul is the best republican of the bunch, and as a registered Republican I only had a say in the Republican Caucus.

I figured that the experience alone was worth the price of attending. I had specifically registered as a Republican in order to support Paul, so I figured I may as well do just that. It was either that or do nothing, so I picked do something.

Next time I do something "for the experience", I may want to think twice.

Continue reading ‘My First Caucus: The Tale Of The Reluctant Delegate’ »

Changing Logging Behavior of Rails via Extensions

One of the nicest things about Ruby is how well it supports metaprogramming. You can dynamically, at runtime, change the behavior of any other class or module in the system, even private methods.

When I was first learning Ruby, this seemed like a flaw, and while I still feel that this ability can be abused, it is definitely handy.

I'm going to explain a simple method of changing the behavior of part of Rails by a real-life example from work.

For a Ruby on Rails project I'm currently working on, we had a somewhat uncommon requirement. We're dealing with a lot of data, which we store for other companies. For various reasons, one of the concerns is that we may be subpoenaed and forced to provide all of our records for legal reasons. In order to fully protect the identities of our customers, our system was designed around never actually storing any identifying information about our customers. Instead, customers get a special code that identifies them, and we only have the ability to know the code, but we can't tie the code to any specific organization. This may seem like a strange restriction, but for our application it was important.

This important aspect of the project had a number of implications for the design and implementation of the system, but in this post I'm only going to talk about one of them. IP addresses, when recorded along with the time that an IP address accessed the system, could be used to make educated guesses about the companies using the system. While the system itself does not record IP addresses or timestamps for hits, the web servers themselves do. Modifying Apache not to log this kind of information was trivial, but one glaring issue remained.

In production mode, when an error occurs in the system, a log entry is created in production.log, which tries to provide details that the developers can use to figure out why the error occured. This log contains a stacktrace, some time information, and various other pieces of data that can be helpful in debugging a critical issue. It also logs the IP address of the user that generated the request that resulted in an error, like so:

Processing PostsController#some_action (for 127.0.0.1 at 2008-01-24 10:23:59) [POST]
  Session ID: b8f0b05d77fc4a5efdc04cf809f810d4
  Parameters: {}

The problem here is that the IP address is logged , and there is no way to change that via a configuration option. I can turn logging off entirely, but I'd like to keep the error information in the event that the system actually does have a bug in it.

Luckily, the design of Ruby allows us to actually override this behavior relatively easily, and I'm going to explain how.

Step 1: Figure Out What You Want To Change

For this problem, figuring out what needed to be modified was relatively easy. I was able to simply grep for "Processsing " inside of /usr/lib/ruby/gems/1.8/gems to find the file that was responsible for printing this line to the log. It turns out that it was the base.rb file inside of action_controller. Opening this file and searching revealed this method:

def log_processing
  if logger && logger.info?
    logger.info "\n\nProcessing #{controller_class_name}\##{action_name} (for #{request_origin}) [#{request.method.to_s.upcase}]"
    logger.info "  Session ID: #{@_session.session_id}" if @_session and @_session.respond_to?(:session_id)
    logger.info "  Parameters: #{respond_to?(:filter_parameters) ? filter_parameters(params).inspect : params.inspect}"
  end
end

This was a private method on the Base class inside of the ActionController module. The rest of the process is quite easy.

Step 2: Write The Override

To override something, you simply define a new method as though it never existed before. These get qualified in the same as defining any method on a class or a module. Here is what mine looked like:

module ActionController
  class Base
    private
    def log_processing
      if logger && logger.info?
        logger.info "\n\nProcessing #{controller_class_name}\##{action_name} (for [FILTERED]) [#{request.method.to_s.upcase}]"
        logger.info "  Session ID: #{@_session.session_id}" if @_session and @_session.respond_to?(:session_id)
        logger.info "  Parameters: #{respond_to?(:filter_parameters) ? filter_parameters(params).inspect : params.inspect}"
      end
    end
  end
end

As you can see, I am simply defining a method called "log_processing" on the Base class inside the ActionController module. When Ruby interprets the above code, it will define this method, overwriting the method if it already exists. All I did was change the IP address to say that it was filtered. Note that even though this method is private, I am still able to do this painlessly.

The next step is to simply get Rails to run over this code and overwrite the existing log_processing method.

Step 3: Making It Load

There are a lot of ways you can do this. The ideal way is to create a plugin in vendor/plugins that contains this code. Rails will automatically run over the code at the correct time. This is a slightly more complex approach than I'd like to cover here, however, so we're going to just try and get this into the system as quickly as possible.

I've found that once you start doing this sort of stuff, you like to have a single place to keep all the behavior modifications you are using. Sometimes you'd like to simply add a method to a class, or change part of Rails. These changes are basically all unrelated, except that they are important for your application. For this reason, I like to keep them all together in a single file so that it's easy to see what has been changed/added. Obviously if you wind up making a lot of changes, you should make a plugin instead, particularly if the changes might be useful in other rails apps.

Save the above code into a file called "extensions.rb" inside of the "extras" directory under my rails project directory.

Then, go into your environment.rb file and add this line to the bottom:

 
require File.join(RAILS_ROOT, 'extras', 'extensions')

The reason I suggest the bottom of the file (after the Rails::Initializer.run) is that you want to make sure all of the rails libraries are loaded first, otherwise they will overwrite YOUR method, instead of the other way around.

That's it. Now, whenever you run rails (even in script/console), your changes will be reflected. This successfully causes the error log to leave the IP address out of what is recorded.

This is not something that should be done a lot in your application. Changing the behavior of core parts of rails will likely confuse other developers on your team. That's why, if this method is employed, I believe you should keep these changes to a minimum, and keep them all in one place.