Redline Software Inc. - Winnipeg's Leader in Ruby on Rails Development

Plugins Moved to Github

We finally got around to moving our plugins from our old SVN machine into Github. Although we’ve been using Git for a long time, we were slow on moving our plugins for some reason.

github.com/redlinesoftware

Team Registration Changes

A minor change has been made to Redzone Leagues with regards to the team signup process. When a user registers a team, they will now receive an confirmation email with an activation link that they will need to load in order to complete the registration process.

The reason for this change was to ensure that team representatives have current email addresses entered into the system. League administrators often need to contact team representatives, so we want to make sure those emails are as current as possible. As always, users can update their email address by clicking “My Profile” at the top of the site. If they need to resend a team activation email, they can do so from their “My Teams” page, which is linked at the top of the site after they create a team.

If you are a league administrator adding a new team, you will not need to complete the activation process. This is done to make the team creation by administrators as quick as possible.

Extending Named Scopes

Quick code tip…

I’m using named_scope with a lambda as the 2nd paramater, but I also want to extend the named_scope with some custom methods.

1
2
3
4
5
6
named_scope :for_league, lambda{|league_id| {league conditions} } do
  def default
  end
  def do_something_custom
  end
end

I use the same extended methods in more than one place, so I figured I’d use something similar to the :extend option used with association methods like has_many, but I can’t pass an :extend option if I’m also using a lambda.

The way around this is to just include the methods directly in the block.

1
2
3
4
5
6
7
8
9
10
module Associations
  def default
  end
  def do_something_custom
  end
end

named_scope :for_league, lambda{|league_id| {league conditions} } do
  include Associations
end

Works like a charm. Now I can just reuse the Associations module where I need it.

Nginx Expiry for Ruby on Rails

Many examples I see for setting the expiry header with Nginx look something like this…

1
2
3
4
5
6
location ~* (stylesheets|javascripts|images) {
  if (-f $request_filename) {
    expires max;
    break;
  }
}

This example runs a regex against the location of the incoming query for a path that contains one of the rails asset types. If the requested file exists then the expiry header is set. max here just tells the server to set the expiry date to the maximum value possible. You can set it to 10 years or any number of days if you prefer.

The issue with this is approach is that it is a “catch all” and ignores the query string on an asset if one exists. Both /stylesheets/styles.css?1234567890 and /stylesheets/styles.css are treated the same using this method of expiry.

If an asset is retrieved from the server (query string or not) and the expires header is set, the next time the file is referenced in the browser, the file will be loaded from the browser cache instead of the server. Now if the asset is modified on the server, rails will update the query string and the browser will recognize the difference and re-fetch it from the server. For the assets that don’t have an associated query string (like /stylesheets/styles.css), the browser will have no idea anything has changed and still load the file from it’s cache. This can cause styles or scripts to go out of sync between the server and the browser causing some nasty issues for the user.

So essentially, we only want to set the expires header on the assets that have a query string and not set the expires header on assets that don’t have one. This way the browser will always retrieve the most up to date version of a file.

What we’re looking for are 2 conditions that need to be satisfied before we set the expires header:

  1. The file is one of the asset types
  2. The query string contains the 10 digit timestamp

So let’s update the config to only set the expires header on asset files that have the 10 digit query string.

1
2
3
4
5
6
7
8
9
location ~* (stylesheets|javascripts|images) {
  if (!-f $request_filename) {
    break;
  }
  if ($query_string ~* "^[0-9]{10}$") {
    expires max;
    break;
  }
}

Here we use the same regex as before to find one of the asset types, but now instead of checking if the file exists, we check if it doesn’t exist. If the file doesn’t exist, we break out and don’t set the expires header which is fine. If the file does exist, then we don’t break, but continue evaluating our conditions because we’ve now satisfied condition 1 as we are looking at one of our asset files. The next thing we do is check the query string for a 10 digit pattern. If the check is successful then we’ve also satisfied condition 2 and can set the expires header for the file.

Now when we update an asset file on the server and Rails updates the query string, the server will re-fetch the file and set a new expires value… perfect.

If you want to check the file extension instead of their directories, you can use the following configuration instead. Note the location regex change.

1
2
3
4
5
6
7
8
9
location ~* \.(js|css|jpg|jpeg|gif|png)$ {
  if (!-f $request_filename) {
    break;
  }
  if ($query_string ~* "^[0-9]{10}$") {
    expires      max;
    break;
  }
}

Player Data and OT Pts

Two new features have been added to Redzone.

  1. You can now download your player data from the admin users page. The file can be imported into a spreadsheet and formatted however you see fit.
  2. A new overtime win point setting has been added along with the other point settings which are available from the admin dashboard.

Redzone Update

Just a quick note to mention some small updates recently made to Redzone…

  • Division Stats
    - You can now view the stats for an entire division. The default it still the top 10 for all divisions, but if you’re looking for an extended list of stats, you now have that option.
  • Allow multiple contacts
    - This is a really minor change, but before you couldn’t add a user more than once on the contact page, but now you can.
  • Division email
    - An additional email option has been added to the teams page. You can now send an email to an entire division if required. (This is only accessible to administrators)

Team Roster Enhancements

It’s been a little while since our last feature update post, but we’ve recently added a couple of new enhancements to the team rosters.

Player number support has now been added. An administrator or team contact can enter in player numbers for their team and these will appear on the team page and will also automatically appear on game score cards.

The second addition is the ability to “disable” a player on a team. An administrator or team captain may want to do this if a player no longer plays on a team or have been “traded” to another team, etc. Disabled players are removed from the team email messages as well as the list of eligible players for a game when entering stats.

Both of these features are only available to the league administrator and the team contact. Simply press the “Edit Roster” button at the bottom of the page for a specific team and you will have the options to specify the player numbers as well as enabling and disabling players using the checkboxes beside each player.

Redzone News & Forum RSS Feeds

We’ve added RSS feeds for news items as well as each forum that you create for your league. There’s also a feed for all of the forums combined. See your browsers docs and/or use your favourite RSS reader to make use of them.

Enjoy!

File_column Image Regeneration

If you use file_column for some projects and find that you want to change the thumbnail sizes that you’ve been using for models, then hopefully this little bit of code can help.

Add this as a rake task and run it as rake "filecolumn:regenerate[Model, field]" RAILS_ENV=production where Model is the model you want to regenerate images for and field is the filecolumn field on the model. The task uses Rake arguments, so you’ll need Rake 0.8.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
namespace :filecolumn do
  desc "Regenerate filecolumn images"
  task :regenerate, :model, :field, :needs => :environment do |task,args|
    if args.any?{|k,v| v.blank?}
      puts "Usage: #{task.name}[Model,field]"
    else
      klass, field = args.model.constantize, args.field

      klass.all.each do |obj|
        puts "Regenerating #{klass} #{obj.id}"
        next if obj.send(field).nil?
        state = obj.send("#{field}_state")
        state.instance_variable_set(:@just_uploaded, true)
        state.transform_with_magick
      end
    end
  end
end

The code essentially boils down to 2 lines…

  • setting @just_uploaded to true on the state object
  • calling the transform_with_magick method on the state object