Skip Links

Blog

Posts tagged with "ruby".

Enterprise Ruby

Sid

Sid

26 Oct 2009 15:09

This announcement from Phusion on Ruby Enterprise Edition (REE) was posted this week, and it’ll be interesting to see the uptake and also what other REE offerings appear in the next few months.

We’ve no plans on doing anything with REE at the moment as we go at the pace of our Ruby hosts but we’d would be interested to hear from anyone who is using it or plans to use it.

Tagged in: ruby, performance

Does Ruby call by reference or by value?

Stephen

02 Nov 2009 15:20

There is a surprising amount of discussion on this topic, some with convincing examples supporting one or other side of the fence. So I thought I’d have a go at explaining it…. Ruby uses call-by-value. There I’ve said it, now for the backup.

It hinges on the clarification between call-by-reference and call-by-value where the value is a reference which Ruby uses.

Call-by reference – means that the actual reference is passed to the method. This allows the reference (and/or the referenced object) to be manipulated in the method and those changes to be reflected once the method returns.

Call-by-value where the value is a reference – means a copy of the reference is passed to the method. The scope of this reference copy is just within the method. This allows the referred-to object to be manipulated via the reference copy and those changes would be reflected on return of the method BUT any changes made to the reference copy itself will not be reflected on return of the method.
E.g. assigning a new object to the reference copy would only have the scope of that method, i.e. on return the original reference would be unchanged.

I think this explains the behaviour in the examples I have seen.

Tagged in: ruby, Call by Value

Oddity with Rails Memory Store cache

Sid

Sid

25 May 2010 20:47

A bit of a specialist post, but I was caught out today by odd behaviour with the using the memory_store cache in Rails.

This is a code snippet from our controller method

cache_key = 'current_standings'
@standings = Rails.cache.read(cache_key)
# check cache
if @standings.nil?
 # ... fetch the data
 # add to the cache
 Rails.cache.write(cache_key,@standings)
end

The problem I found was that the second time through, i.e. on the cache read, the items in the cache were nil.

When I tested the items in the cache there were the number expected, and they were the right type but they were just not populated. Putting the object in and out of the cache in the console was fine.

In the end, and after a lot of error and some trial, I found that I needed to set the config.cache_classes property to true in the development.rb file. An unfortunate side-effect of this is that hot deploy is no longer hot and I need to restart the server to pick up changes but at least the cache works okay.

I’m guessing that with each request the cache (or at least the variables in there were being blasted) but would be interested in hearing from anyone else who has experienced the same/similar.

Tagged in: ruby, rubyonrails, RoR, memory_store, cache

Olympic Tickets Predictor - Code Review

Sid

Sid

17 Jun 2011 20:13

After getting a mail from London 2012 telling me that they would tell me what tickets we’d got soon I finally broke and decided that I needed to work out what tickets we’d got now!

I knew how much we’d been charged and the events that we’d applied for. Also, it seems that there is a 6 quid charge to deliver the tickets (I’m expecting my postman dressed as a traffic cop for that) so that means it was just a case of working out which combinations of tickets add up to that.

This is another example of where Ruby makes something that could be tedious or complicated nice and easy by having methods on their collections that make this a breeze – namely Array.combinations(1) where you can do “n Choose p” calculations and also Array.inject which makes summing easy. Data lines aside there’s probably more lines of comments than of code.

The outcome was just a single combination (there are either-ors as some of events are priced the same):

  • Athletics
  • Volleyball or Beach Volleyball
  • Rowing or Basketball
  • Football

which is good news as I was really hoping for athletics (and beach volleyball)! I’ve looked through the code a few times and can’t find any issues but any errors gratefully received before I get too excited!

# olympic tickets helper

events={}
# populate a hash of event prices and the event(s)
# 
events[160]="(volley or beach)"
events[500]="athletics"
events[380]="athletics"
events[120]="football"
events[200]="cycling"
events[220]="bball"
events[260]="athletics"
events[134]="(rowing or bball)"

# pull the prices out
prices=events.keys

# the total taken from the credit card
total = 920

# according to the website 6 quid is taken off for delivery (what a rip-off!)
delivery_charge = 6

# the price of the tickets is the remainder
remainder = total - delivery_charge

# 
# this loop controls the number of combinations from the 8 price events
# we know that no single event is over the remainder so start from 2. we also know
# that all 8 are over the remainder (as probably are 7 but too tiresome to work out) so
# only need to work out from 8 choose 2 to 8 choose 7 
#
for i in (2 .. 7)

	# prices choose i ... turn to an array to check each
	possibles = prices.combination(i).to_a

	# for each of the combinations
	possibles.each do |posse|

		# ... find the sum of the prices and check whether they match the remainder
		if (posse.inject(0) {|sum,v| sum+v}) == remainder

			# if they do then they are a combo (possible cos there are multiple events at the same price)
			puts "Possible combo:"
			posse.each do |p|
			 puts "#{events[p]} @ #{p}"
			end

		end #end if

	end # end inner
	
end # end outer

# don't forget the delivery charge
puts "delivery @ 6"

Update 20/7/2011

We ended up with Athletics, Volleyball, Rowing, and Football. So good from a code point of view not so good as I’d convinced myself that we’d be going to the basketball! Still very lucky to get the tickets and really looking forward to it!

Tagged in: ruby, olympics

Rails: Testing models based on db views

Sid

Sid

22 Sep 2011 09:56

Rightly or wrongly I get the impression that most RoR engineers ignore database views and would rather they didn’t exist. I’m neutral about db views but there are times when they have their place. We use them in Zico our online survey app for some of the survey stats and gamification we provide.

Last week I was baking some of this is to the app and realised whilst it is simple enough to map a model on to a db view by just treating the view like a table, it was a different matter when it came to testing. Important note: you can only “treat db views like a table” if it is a single-table view or your model is read-only].

The problem with testing views is that when you create your test database, Rails creates the view as a table in the test database. In most circumstances this means your test will fail as your view-now-table won’t have the data in it (the data is selected with a db view as opposed to inserted ). This fails both for test dbs created through migration and structure cloning. Annoying!

I thought of several ways around it (confession: including removing the tests) but looking harder saw that it was possible to copy the view to test db as a view with a bit of monkey-patching. This example only covers MySQL but the adapter classes are there for all the other dbs and once you know how to pull metadata from your db it’s pretty easy.

First … how Rails copies your database structure to test

There are two ways in which Rails copies the db structure over to test. It either runs the migrations on the test database (ignoring the execute sql ones that create db views — #fail) or it copies the structure from SQL (and in this case it turns views in to tables — #fail)

We are going to choose the second way i.e. to clone the database and change the cloning (for MySQL dbs) so that it includes views.

First off we need to tell Rails to clone the database from SQL and we do this by adding this config.active_record.schema_format = :sql to our application.rb file (or similar in Rails2)

You then use the rake db:test:clone_structure command to copy your database structure (i.e. not data these will be via your fixtures) from dev to test.

Next … how Rails maps models

As you might imagine, Rails gets the info need to based models on tables from the database metadata – i.e. info about the tables and columns amongst other things. Every RDBMS has this and you can read about MySQL metadata in the manual.

By default Rails doesn’t pull metadata info about db views (for good reason as unless a single-table view you won’t be able to create or update). However, if your only have the need for read-only models for your views then you can get Rails to do the hard-work for you rather than write the model by hand.

The metadata queries can be found in a set of classes that inherit from ConnectionAdapters::AbstractAdapter. The Rails3 adapter is called Mysql2Adapter and is in the mysql2 gem.

This class defines a method called structure_dump which queries the metadata tables and pulls back all matching tables. We need to re-open that class and override the method to pull back both tables and views.

I added the following to a new file that I put in the config/initializers folder (put in your environment in Rails 2)

support_db_views.rb


module ConnectionAdapters

class Mysql2Adapter < AbstractAdapter # SCHEMA STATEMENTS ======== def structure_dump if supports_views? sql = “SHOW FULL TABLES WHERE Table_type IN (‘BASE TABLE’,’VIEW’)” else sql = “SHOW TABLES” end select_all(sql).inject("") do |structure, table| view = table‘Table_type’ == “VIEW” table.delete(’Table_type’) if view structure += select_one(“SHOW CREATE VIEW #{quote_table_name(table.to_a.first.last)}”)“Create View” + “;\n\n” else structure += select_one(“SHOW CREATE TABLE #{quote_table_name(table.to_a.first.last)}”)“Create Table” + “;\n\n” end end end end end

Basically the method used to read through the metadata and pulled the structure definition (i.e. the CREATE statements) for tables and then collected these for running in to test. We have just changed the metadata query to include views as well as tables — sql = “SHOW FULL TABLES WHERE Table_type IN (‘BASE TABLE’,’VIEW’)” — and then when we loop through the objects, if we find a view we pull its create statement. Simple!

As we’re re-opening our abstract class we need to redefine the connection method that it provides. I won’t put the code in the post but you can download a copy here

Finally … was it worth it?!

As a rule I tend to avoid db views for new Rails apps in that it tends to make life a bit more difficult. There are good reasons to use db views though and if you want (or have) to do use them and you want to write full tests (which of course you do) then this isn’t a bad way to support it.

Tagged in: ruby, Ruby on Rails, database views, gamification, online surveys, viral surveys