Form Select Helper in Ruby on Rails

It's crazy how little documentation there is on using selects (drop down lists) inside form-helpers in Rails.  So, it can get quite confusing when it comes to using the different select helpers; select, select_tag and collection_select.

In order to address this inadequate documentation and examples, I thought I would post here, some of the differnces between them with some examples so you can choose for yourself, the best one to use.

<select name="gender"> <option value="1">Male</option> <option value="2">Female</option></select>

The selection box has some key parts, the name, which is required, and used by the browser when submitting the <select> choices to the server. The option tags, each of which are made up from a "value" and "text" pair, the "value" to identify the select item in the server, and the "text" which will be displayed to the screen.

There are three different select form helpers in ruby on rails, "Select", "select_tag" and "collection_select". Let's compare them.

select(object, method, choices, options = {}, html_options = {})
Defined in ActionView::Helpers::FormOptionsHelper

<%= select( "payment", "id", { "Male" => "1", "Female" => "2"}) %>

Select can be used in conjunction with a model object as seen in this example, an instance variable is passed into choices, but is being converted into an array of arrays.

<%= f.select :gender_id, @genders.map {|r| [r.name,r.id] } %>

Use select_tag when you require a drop-down selection box populated with data not sourced from a database, and are happy to hard code the default selected option tag. Select_tag should also be used when you want to process your form as a GET, rather than a POST.

<%= select_tag "payment", options_for_select([ "Male", "Female" ], "Male") %>

or

<%= select_tag "payment", options_for_select(%w{ Male Female }) %>

You can also do multi-select boxes:

<%= select_tag 'payment[]', options_for_select(@genders),  :multiple => true, :size => 3 %>

(where the controller defines @genders as a hash of values).

In this example the gender methods are being added to the select box via a model object, notice how we use the option, :prompt to add an additional option tag to the select box, which will be selected by default. Note that if @object.method matches one of the option tags, this will be selected by default, and :prompt wont appear in the list.

<%= collection_select(:gender, :id, @genders, :id, :name,  options ={:prompt => "-Select a gender"}, :class =>"gender") %>

In sum:

Use select when you require a basic drop-down selection box populated with data not sourced from a database.

• The object is the name of an instance variable. This is typically a model object (singular name of the table whose data your displaying, or in other words, the table record).
• The method is the attribute of that instance variable. This is typically a field/column of the table whose data your displaying (really an ActiveRecord method).
• Together the object and method specify the name of the select statement in the generated html choices can be any enumerable object e.g arrays and hashes and results of database queries, and contains the option tags for the select box.
• The optional options argument takes various "options" some of which are listed below in the examples.
• The optional html_options argument allows css to be used for styling the select box.
• If one of the option tags in choices matches @object.method, that option tag will be selected.

Use collection_select when you require a drop-down selection box, whose source is a model/object

• The object is the singular name of the table whose data your displaying (the table record).
• The method is the field/column of the the relevant data (really an ActiveRecord method).
• Together the object and method specify the name of the select statement in the generated html collection takes the option tags for the select box, this can be a hash or array.
• The value_method is the field/column to use for the value of the option tags in your html.
• The text_method is the field/column to use for the visible text of the option tags in your html.
• The optional options argument takes various "options" some of which are listed below in the examples.
• The optional html_options argument allows css to be used for styling the select box.
• If one of the option tags in collection matches @object.method, that option tag will be selected.

Some of the content for this post came from here - check it out for a more detailed explaination of the differences between the 3 select form helpers.

Disabling Censorship in the Aussie Version of the L4D2 Demo

If, like me your a slave to the ignorance and intollerance of Michael Atkinson and are stuck with the borked, "censored", Aussie version of Left4Dead 2 - have hope.  As expected, I don't think Valve has gone to extreme lengths to "lockdown" the censroship of L4D2.

It's as simple as changing a single character in 2 files.

1. First, download and then run the Left4Dead 2 demo.
2. Quit (you don't have to play it, the menu is enough.
3. Goto your "steamapps\common\left 4 dead 2 demo" directory.  On my machine this folder is in "C:\Program Files (x86)\Steam\steamapps\common\left 4 dead 2 demo".
4. Edit the steam_appid.txt file and change "590" to "510".
5. Goto your "\steamapps\common\left 4 dead 2 demo\left4dead2" folder.
6. Edit the steam.inf file in notepad (or text editor of your choice) and change the "appID=590" line to "appID=510".
7. Go back to the "\steamapps\common\left 4 dead 2 demo" folder and run the "left4dead2.exe" file.

You will need to run the game from the exe directly for this hack to work, and steam will report the game as "Left4Dead Dedicated Server" but, despite these, you should have a 100% bona-fide proper version.

Now while this works (and I am grateful that it does) I should never have had to do it.  Australia needs a R rating for video games.  We are one of the few countries that don't.  And its not about getting raunchy or violent games - its about responsibility.  15 year old children shouldn't be playing even the censored version of the game - plain and simple.  There are many other examples of games which are marketed and sold to 15+ year old children which simply shouldn't be (Doom 3 for example).

And the fact is we would have an R rating except for the illinformed and rediculous stance that the Office of Film and Literature Classification has taken with video games. Video game classification in Australia is the most strict in the Western World in terms of not having an adult's rating (R18+). Currently only Michael Atkinson, South Australian Attorney-General opposes the R18 classification introduction and is also blocking the release of a public paper that canvasses the opinion of the Australian public on whether or not an R18 classification should be introduced.

It staggers me that 1 person can get so much power to effect so many people through inaction.

It's unconscionable.   Immoral.  And Irresponsible.

How To Install BootCamp 3.0 on Windows 7 x64 (on a 2008 MacBook)

Yes you can - but not directly.  To install boot camp 3.0 on Windows 7 x64 follow these instructions.

1. open command prompt in administrator mode
2. type "net user administrator /active:yes" hit enter
3. log out then log in as "administrator"
4. then open cd and navigate to "bootcamp/drivers/apple/"
5. run "bootcampx64"
6. once done reboot, logback in and turn off administrator account by entering "net user administrator /active:no"

viola! boot camp 3.0 on x64!

This successfully installed on my late 2008 model uni-shell MacBook (the non-pro single cast aluminium one).  Windows 7 managed to get most of the drivers by default, which was a refreshing change from XP and Vista (including the wireless drivers), but once BootCamp had installed the audio was fixed, and everything was great.  I installed the GeForce 9M drivers from nvidia.com and I was in action.

Watchout Folks, Dodgy Teachers Will "Get" You on Facebook (Apparently)

I'm sorry but things like THIS - really pisses me off!

TEACHERS have been banned from contacting students on Facebook, MySpace, YouTube and other social networking sites amid growing concern over inappropriate relationships.

There are so many reasons why this is wrong, that I'm not even really sure where to start. I am further infuriated by the comments on that article. Are these people serious? Really? Dodgy teachers engaging in inappropriate conduct with students, do not do so in open and transparent mediums. They'd actively disengage from these becasue they'd get caught! Dark and dodgy people cannot exist in the light. They run from it.

It's funny how the general public demand the goverment to protect them and their children, despite having little or no understanding of social media (and technology more generally). They don't understand the medium and they don't understand the minds of those who would seek to target their children. Becasue if hey did, they'd understand that its a futile and pointless policy. Much like the proposed "clean feed".

Grr....this kind of trivial, thoughtless, primitive thinking really makes me mental!

MacBook Won't Eject CD (a.k.a My Mac ate my CD)

While using a Windows VM on my MacBook today, I needed some files off a Windows install disk. I put the disk is with no problems, did what I needed to do, and then tried to eject it. You can imagine my suprise when I could hear the drive (making its really ugly crunching sound) and then - no disk.

So I pressed eject again. Nothing.

And again. Nothing. hrmm. This wasn't looking good.

So I went back to OSX, and the disk wasn't being detected by OSX - despite working fine the VM. I pressed the eject button. Nothing. I logged off (thinking some app had locked the superdrive). Pressed eject. Nothing. Rebooted, holding the mouse button down(I'd heard this does an eject if done on boot) - still nothing.

I was worried.

In a last ditch attempt, I found the terminal command 'drutil tray eject' which made the right sounds, but didn't eject the disk. hrmm, getting closer. I thought to myself "I wonder if it's stuck on something?" and then (and I have to admit that I felt like i was molesting my Mac) - stuck the tip of a plastic cable tie into the slot poked around a bit (a little, just enough to feel some resistance inside) and tried 'drutil tray eject' again in the terminal window.

The disk ejected, like a good little MacBook.

Fixing Audio Problems in Windows 7 x64 on MacBook (Not Pro) and Boot Camp

I was fortunate enough recently to get a license of Windows 7 x64 Home Premium which I promptly installed on my (non-pro) 15" MacBook.

The install through the OSX Boot Camp wizard went really smoothly and wireless and most other drivers worked out of the box. However, on my early 2008 MacBook, the audio driver did not work (instead only red light constantly came out of the audio jack). Obviously, the driver provided by Boot Camp is not the right one. From my experiences using XP on my Mac, I remembered that the audio card is made by Realtek. After lots of googling, I downloaded the driver directly from Realtek and it worked. Here is the download link. The one I downloaded is Vista Driver (32/64 bits) Driver Version R2.14. Extract the files and run the setup.exe.

BTW, if you are looking for some older versions, you can use this ftp site.
ftp://202.65.194.211/pc/audio/. This is a mirror site used by Realtek. Note that the download speed is kinda slow, so be patient.

PostgreSQL Performance Optimization

Recently, I've been dealing with databases at work which have millions if not BILLIONS of records.  So as you can imagine, having Postgres running smoothly and as quickly as possible, is of utmost importance.  So, as a guide, and compiled from a number of sources. Obviously faster, better, bigger hardware will make the database faster, but there are often other steps you can take to get PostgreSQL working a bit smarter, and a bit harder. The first place to start with Postgres optimization is the Postgres configuration. The list below provides a guide (use at your own discretion) of some of the primary settings relating to resource use. Even small tweaks can have a big impact on server performance.

max_connections. This option sets the maximum number of database back end processes to have at any one time. Use this feature to ensure that you do not launch so many back ends that you begin swapping to disk and kill the performance of all the children. Depending on your application it may be better to deny the connection entirely rather than degrade the performance of all of the other children.

shared_buffers. Editing this option is the simplest way to improve the performance of your database server. The default is pretty low for most modern hardware. Shared buffers defines a block of memory that PostgreSQL will use to hold requests that are awaiting attention from the kernel buffer and CPU. The default value is quite low for any real world workload and need to be beefed up. However, unlike databases like Oracle, more is not always better. There is a threshold above which increasing this value can hurt performance.

PLEASE NOTE. PostgreSQL counts a lot on the OS to cache data files and hence does not bother with duplicating its file caching effort. The shared buffers parameter assumes that OS is going to cache a lot of files and hence it is generally very low compared with system RAM. Even for a dataset in excess of 20GB, a setting of 128MB may be too much, if you have only 1GB RAM and an aggressive-at-caching OS like Linux.

Note that on Windows (and on PostgreSQL versions before 8.1), large values for shared_buffers aren't as effective, and you may find better results keeping it relatively low (at most around 50,000, possibly less) and using the OS cache more instead.

It's likely you will have to increase the amount of memory your operating system allows you to allocate at once to set the value for shared_buffers this high. If you set it above what's supported, you'll get a message like this:

IpcMemoryCreate: shmget(key=5432001, size=415776768, 03600) failed: Invalid argument This error usually means that PostgreSQL's request for a shared memorysegment exceeded your kernel's SHMMAX parameter. You can eitherreduce the request size or reconfigure the kernel with larger SHMMAX.To reduce the request size (currently 415776768 bytes), reducePostgreSQL's shared_buffers parameter (currently 50000) and/orits max_connections parameter (currently 12).

effective_cache_size. This value tells PostgreSQL's optimizer how much memory PostgreSQL has available for caching data and helps in determing whether or not it use an index or not. The larger the value increases the likely hood of using an index. effective_cache_size should be set to an estimate of how much memory is available for disk caching by the operating system, after taking into account what's used by the OS itself, dedicated PostgreSQL memory, and other applications. This is a guideline for how memory you expect to be available in the OS buffer cache, not an allocation! This value is used only by the PostgreSQL query planner to figure out whether plans it's considering would be expected to fit in RAM or not. If it's set too low, indexes may not be used for executing queries the way you'd expect.

Setting effective_cache_size to 1/2 of total memory would be a normal conservative setting, and 3/4 of memory is a more aggressive but still reasonable amount. You might find a better estimate by looking at your operating system's statistics. On UNIX-like systems, add the free+cached numbers from free or top to get an estimate. On Windows see the "System Cache" size in the Windows Task Manager's Performance tab. Changing this setting does not require restarting the database (HUP is enough). .

work_mem. This option is used to control the amount of memory using in sort operations and hash tables. While you may need to increase the amount of memory if you do a ton of sorting in your application, care needs to be taken. This isn't a system wide parameter, but a per operation one. So if a complex query has several sort operations in it it will use multiple work_mem units of memory. Not to mention that multiple backends could be doing this at once. This query can often lead your database server to swap if the value is too large. This option was previously called sort_mem in older versions of PostgreSQL.

max_fsm_pages. This option helps to control the free space map. When something is deleted from a table it isn't removed from the disk immediately, it is simply marked as "free" in the free space map. The space can then be reused for any new INSERTs that you do on the table. If your setup has a high rate of DELETEs and INSERTs it may be necessary increase this value to avoid table bloat.  Sets the maximum number of disk pages for which free space will be tracked in the shared free-space map. Properly adjust upward to make vacuum runs faster and eliminate/reduce the need to “vacuum full” or “reindex”. Should be slightly more than the total number of data pages which will be touched by updates and deletes between vacuums. Requires little memory (6 bytes per slot), so be generous adjusting its size. When running vacuum with “verbose” option, DB engine advises you about the proper size.

fsync. This option determines if all your WAL pages are fsync()'ed to disk before a transactions is committed. Having this on is safer, but can reduce write performance. If fsync is not enabled there is the chance of unrecoverable data corruption. Turn this off at your own risk.

commit_delay = and commit_siblings. These options are used in concert to help improve performance by writing out multiple transactions that are committing at once. If there are commit_siblings number of backends active at the instant your transaction is committing then the server waiting commit_delay microseconds to try and commit multiple transactions at once.

random_page_cost. Sets estimated cost of non-sequentially fetching. Lower it to influence the optimizer to perform index scans over table scans.

Note that many of these options consume shared memory and it will probably be necessary to increase the amount of shared memory allowed on your system to get the most out of these options.

If you are after a more comprehensive list of Postgres' Tuning and Performance, the PostgreSQL documentation has a great wiki on the subject.

The other place that often gets overlooked for performance enhancement, is the actual database queries themselves.  I must admit ignorance myself to the Postgres inclusing of the 'EXPLAIN ANALYSE' keywords preceding any SQL statement which returns a very comprehensive trace of the query through the database entry, including specific timings, index use etc, which can be a big eye opener to tables, sorts or indexes which maybe being used incorrectly, or just being slow.  Here is an example of explain analyse on a SQL statement on a very large database:

EXPLAIN ANALYSE SELECT items.etag, subscriptions.subscription_dataFROM items, subscriptions WHERE items.item_id = subscriptions.item_id;

returns the entire query plan, like:

"Hash Join  (cost=1.29..22.38 rows=50 width=64) (actual time=0.055..0.084 rows=21 loops=1)"
"  Hash Cond: (subscriptions.item_id = items.item_id)"
"  ->  Seq Scan on subscriptions  (cost=0.00..17.70 rows=770 width=36) (actual time=0.010..0.012 rows=21 loops=1)"
"  ->  Hash  (cost=1.13..1.13 rows=13 width=36) (actual time=0.027..0.027 rows=13 loops=1)"
"        ->  Seq Scan on items  (cost=0.00..1.13 rows=13 width=36) (actual time=0.008..0.014 rows=13 loops=1)"
"Total runtime: 0.154 ms"

Scale is the New Black

Cross-posted from the Particls blog.

Over the past two weeks, the Faraday Media development team have been hard at work migrating all our products and initiatives into a new datacenter.  The new data center was much more suited to Faraday Media technology - much easier to scale, much faster and more reliable.

As part of our efforts, we’ve finally had the opportunity to give Particls and the Engagd platform their own dedicated servers, effectively quadrupling our processing capability.  This will allow us to service our partners and customers with increased reliability and confidence.

We’ve taken the opportunity with the new servers, to finally move our blogs off Blogger and onto a hostedWordPress solution, giving us far more flexibility with our blogs and presentation.

One problem, however, after we upgraded to WordPress 2.6, was that when we changed the permalink settings (to something more tollerable than ‘?p=x’) suddenly, index.php worked fine, but any other page reported as ‘not found’.  After serverl long hours Googling for the answer, there was lots of “answers” for WordPress on Apache (specifically about correct access to the .htaccess file and ensuring the correct PHP/Apache modules are installed) - but none about how to solve these issues on IIS.  It turns out that there are a number of known issues with 2.6 on IIS, which are now solved with the release of WordPress 2.6.1.

With most of our migration issues now sorted, we can now confidently continue to deliver our attention and data portablity solutions to the masses secure in the knowledge that our services are scalable and our bandwidth is plenty.

It's Just Too Noisy In Here

Until last night, I was following over 1100 people on Twitter. I love Twitter, but lately, I am feeling increasingly like every-time I open Twirl, I am being screamed at by 100 people at once.  It was becoming all nigh to follow what the people I really care about (@MrsAngell, @ChrisSaad, @michaelmcneill@DallasClark and @StephenKelly to name a few) where talking about.

Basically, as much as I've loved talking to you all, I just can't keep it up.  In a society which is approaching economies of scarcity, I have reached a saturation point where my Twitter value is dropping because I can't hold meaningful, deep, 140 character conversations with people anymore.  My Social Graph has become so wide that it barely holds definition anymore.  Too many trivial relationships, talking too loudly.

So starting last night, I've started a mass excommunication of my followers.   I have already culled over 300 people (thanks to Twitters recently improved interface tweaks).

I am trying to be selective.  If you have *something* in common with me, professionally, personally, intellectually or geographically; then you're probably safe.  I will an try to ensure that I follow people I converse with (so any @ replies count).

So, I am sorry if your one of the exiled, It's not personal - It's Just Too Noisy In Here!

Update

Extracting Specific Date-time Components in Postgres

When programming, sometimes it's useful to extract various time components from a Date-time field in SQL queries.  For example, you might want to filter the date field by, hour, or year (or both).  Fortunately, Postgres has a easy way to pull this data out within the query itself:

SELECT EXTRACT(hour FROM a_datetime_field) FROM a_table;

If the field was the value '4/5/2009 13:09:00' then that above query would return "13" in the select.

In a stranger, practical example, I was moving a database from one server to another and for some unknown reason, all the dates in a table were fudged so that instead of being the year 2009, it was 142009, and the seconds were also stuffed up - the result being that any queries I ran against the table threw ADO.NET exceptions because the dates couldn't be parsed properly.  I needed to run a query like this one to set things right again:

UPDATE atable  SET datetimeadded = cast( '2009-' || EXTRACT(month FROM datetimeadded) || '-' ||    EXTRACT(day FROM datetimeadded) || ' ' || EXTRACT(hour FROM datetimeadded) || ':' ||    EXTRACT(minute FROM datetimeadded) AS timestamp),  datetimeupdated =  cast('2009-' || EXTRACT(month FROM datetimeupdated) || '-' ||    EXTRACT(day FROM datetimeupdated) || ' ' || EXTRACT(hour FROM datetimeupdated) || ':' ||    EXTRACT(minute FROM datetimeupdated) AS timestamp);

The casts are needed to get the update to cooperate, but basically this recreates the date time piece-by-piece based on the original date-time value.