Thursday 3 December 2009

Options for select

A handy one this, for selections that aren't driven from the DB, but which have a value stored in a DB - and yes, I know that is not good practice ...


<%= f.label :number_colours %>
<%= f.select(:number_colours, options_for_select([ ["CMYK", 4], ["Black & white", 1], ["2 colour", 2], ["3 colour", 3], ["CMYK + special", 5] ], :selected=>@page_assembly.number_colours )) %>


the final :selected=> tag allows you to specify which one gets the lucky selected tag...

Thursday 26 November 2009

It is times like this I love RoR

Declarative_authorization and Authlogic - just the best. That would have taken me days - as it is it only took as long as it did because upgrading RHEL5 to Ruby 1.8.7 (which DA needs) was such a pain.
Works like a dream in my little test set up - now to make it work on the real thing.

Wednesday 25 November 2009

Riiiight ....

Well that was a monumental PITA.
In the end upgrading Ruby caused the gem install to go all haywire. In the end the easiest thing was simply to reinstall all the gems - so now I have two loads of the same gems on my server. Why do I think this is a bad thing and going to come and bite me on my arse someday...?
Of course if RHEL 5 had had the right install of Ruby ...

Tuesday 24 November 2009

Grrrr - upgrading Ruby

Why is the YUM package stuck on 1.8.5? Want to use Declarative_Authorization but it needs Ruby >= 1.8.6. Tried to upgrade but the last thing you must do is to end up with two installs of Ruby on yr server. And the last thing I ended up with was ...
That way confusion and madness lie.
So I hope I have managed to uninstall one and upgrade the existing version to 1.8.7. Of course all of this would have been a whole load easier if YUM had had the right package ...
Oh sod it.
Hasn't worked - need to pass it a path I am guessing in the ./configure - path="/usr/bin" I am guessing ...

UPDATE: No - make that prefix=/usr
I read somewhere that that was a no-no and Linus Torvald himself will come and kick my arse for doing that. Hope not.

Authlogic

Loving it.
Authentication in zero time - and some quite nifty tracking features right out of the box.

Just followed the tutorial - plus the ever-brilliant Ryan Bates on
Asciicasts and it all worked first time. Have to love it.

Now to work out authorisation...

Thursday 12 November 2009

Nested polymorphic associations - 2

Have fought through the undergrowth and am in a clearing - and I can see the way out.
The most important thing is to pay close attention to what
rake routes

tells you. And if you have a job_scannings_batches path - remember to give the objects in the correct order. Rails may be smart, but it isn't that smart.
Have a kludge in place to get the second layer of nesting to work - not sure it is very elegant, but it works. I get the name of the polymorphically associated class and use that to do a custom search
(ie @batchable.Class.name). I can't help but feel I should be able to do it using an association of some kind. However it works so ... (but it feels bad)

Wednesday 11 November 2009

Nested polymorphic associations

My ears are bleeding ...

Slowly getting there, but lordy-oh-lordy nested polymorphism is tricky stuff : things like this
form_for [@job, @batchable, @batch] do |f|

in order to generate the correct form for a URL like this
/jobs/18921/scannings/1/batches/1/edit

We have batches which are either photographic, or scans. They belong to jobs. There is a polymorphic relationship (batchable) between them all.
Then nest all of that inside the jobs so that you only get the batches that belong to a particular job. Fun for all the family...

Wednesday 4 November 2009

command line svn

Working from home and it is a PITA to get ZigVersion to work so use command line SVN. Most of the time it is fine, but it is a bore when you create a new model and have to add a whole bunch of files by hand.

Some searching found this unix beauty
svn st | grep ^? | awk '{print $2}' | xargs svn add

Haven't tried it - but it looks very sweet indeed.
Tip o' the hat to John Duell on Internet creators

Sorting an array - sorted

Had a case where calling in an associated class, but don't seem to be able to determine how Rails sucks the data out of MySql - so have had to sort it after the fact.
This little bit of code seems to do the trick

@jobs.sort! { |a,b| b.id <=> a.id }

This is descending - if you want ascending then swap over b.id and a.id.
Don't ask me what is actually going on - but it works

Friday 30 October 2009

save! and save, update_attributes and update_attributes!

This little bugger ate an hour or so of my day. Had a model with validation on a telephone number field which it should fail if someone puts in letters etc.
For some reason I had changed the update to update_attributes! rather than leaving it as update_attributes (teach you to fiddle with things).
save!/update_attributes!/create! throws an error - and unless you have some way of catching it you will end up with
ActiveRecord::RecordInvalid (Validation failed: Name can't be blank, Name has already been taken, Main number only digits, ., +. (, ), allowed):

instead of the scaffold-like

Let that be a lesson

Thursday 29 October 2009

406 Not Acceptable error on jQuery ajaxSubmit

Doh.
Remember to add format.js to the response block - otherwise it falls over ...

Trick found in find(:all)

What happens if you want to search on an class but by an associated class - so I have a class of printers which are a type of organisation. Organisations have names, printers don't (or rather they do, but they have a name by virtue of being a type of organisation). How do I search on their name?

@printers = Printer.find(:all, :include=>:organisation,
:order=>"organisations.name",
:conditions=>['`organisations`.`name` like ?' , "%#{params[:search]}%"]).paginate( :page => params[:page], :order => 'name')


is how.
Couple of things to note - the :include calls in the associated class - and note the back-ticks (not single quotes) around the field - and also note that it is split in two.
Works like a dream.

jQuery awsome find

Just about forever I have had a real problem with jQuery inserting elements into the DOM, and then getting events bound to the new inserted items.
It seems (a) I am not alone and (b) this is the archetypal newbie question.
Yes there is a FAQ on this. And guess who didn't read it?
the answer is instead of
$("#link").click(function(){
// whatever
})


You do
$("#link").live("click", function(){
// whatever
})

This is going to change how I do jQuery forever. And I am embarrassed to say that I never knew it. Ho hum.

PS.
Another trick
Getting the text of a the selected value of a pulldown:

$('#categories').find(':selected').text()


Wednesday 21 October 2009

collection_select

This guy saved me from tearing out (what's left of) my hair.
Thank you.

Tuesday 20 October 2009

Haven't given up

Just been working on another project.
Complex forms - you have to love them.
Had a problem with having a form updating more than one model - in this case it has to update an address as well.
Devil's own business getting the drop down menu to work - and then found Ryan Bates' comment - I want to marry him ...

Here is the partial to be rendered
<% new_or_existing = address.new_record? ? 'new' : 'existing' %>
<% prefix = "organisation[#{new_or_existing}_address_attributes][]" %>
<% fields_for prefix, address do |address_form| %>

<%= address_form.error_messages %>


<%= address_form.label :address_1 %> <%= address_form.text_field :address_1 %>



<%= address_form.label :address_2 %> <%= address_form.text_field :address_2 %>



<%= address_form.label :address_3 %> <%= address_form.text_field :address_3 %>



<%= address_form.label :town_city %> <%= address_form.text_field :town_city %>



<%= address_form.label :county_state %> <%= address_form.text_field :county_state %>



<%= address_form.label :postcode_zip %> <%= address_form.text_field :postcode_zip %>



<%= address_form.label :country %> <%= address_form.text_field :country %>



<%= address_form.label :live %> <%= address_form.select :live, [['No', false], ['Yes', true]]%>


<% if new_or_existing == 'new' %>


<%=address_form.label :address_type_id %> <%= address_form.collection_select(:address_type_id, AddressType.find_all_by_live(true), :id, :name, {:index=>""}) %>


<% end %>
<% end %>


Then the model is as follows:
def new_address_attributes=(address_attributes)
#handles the address edit form in the edit view
address_attributes.each do |attributes|
addresses.build(attributes)
end
end

def existing_address_attributes=(address_attributes)
addresses.reject(&:new_record?).each do |address|
attributes = address_attributes[address.id.to_s]
if attributes
address.attributes = attributes
else
addresses.delete(address)
end
end
end

def save_addresses
addresses.each do |address|
address.save(false)
end
end


And there is a callback to save the address in the case of an update

after_update :save_addresses

Getting the address_type collection to work was an absolute bugger - it kept rejecting the
organisation[new_address_attributes][]
saying it wasn't allowed. That was when I found Ryan's comment about using the same fields_for thingy and yay - it all works.

Wednesday 23 September 2009

Holy crap that was a mind-f**k

nested forms - you have to love 'em.
Nesting with has_many was not too much of a problem. Follow the railscast and it all seems to work just fine - yes it was fiddly, but in the end it comes good.
Nesting with has_one - a total mind fuck.
With has_many you can use association.build to build all the objects you want and then use yr bog-standard controller to handle it for you with the update.
But has_one has a real gotcha. If you try and create two objects - which you may have to to get round the nil problem when using the form_for thingy, then if you try and use association_build, it updates both of them - immediately orphaning one of them as you can only have one associated object. And then all manner of horribleness starts.
After a long, long, long time screwing around with this - came up with the following:
def client_attributes=(client_attributes)
#this little beaut Returns the associated object. nil is returned if none is found (ie on new).
cl = client(force_reload = false)
if cl == nil
build_client(client_attributes)
else
client_attributes.each do |key, value|
unless key == 'id'
cl["#{key}"] = client_attributes["#{key}"]
end
end
client=(cl)
end
end

It is the normal virtual attribute you use to pick it up from the form, and then whack a method in the model. But you have to handle two different situations - one when it is a new build, in which case you won't have an existing client object - so you can go ahead and build it, and the other time when you do.
Then I have manually gone through the new attributes - and leaving aside the id, taken the new values by hand into a temp object (cl), given it the new values from the hash you pass over, and then save it to the child object (client).
Then when that gets handed over to the controller for the normal update, everything is in the right place and there is peace and brotherly love the world over.

Friday 18 September 2009

redgreen and autoSPEC

Ahhh - the command is autospec, not autotest (RTFM).
Had a problem getting redgreen to work - but commenting out the
require redgreen/autotest inside of ~/.autotest seems to have done the trick

Thursday 17 September 2009

Rspec

Have put off the day long enough. Got a simple new class to build (address class). Going to build it using rspec from the ground up - not use scaffold etc.
Wish me luck.

Thursday 27 August 2009

Testing routes

Here is a little tip

have the following in my routes.rb file

map.resources :jobs do |job|
job.resources :pdfs
end


functional test was failing
Couldn't find Job without an ID

So add this to the functional test

get :show, :id =>@pdf, :job_id => @job.id

Passing the job_id puts it in the parameters hash, but not inside the array for the object.

Monday 24 August 2009

I am starting to hate Factory Girl

Why oh why is it not passing the associated id?
Clearly I am doing something wrong, but wtf is it?

Factory.define :output_type do |f|
f.sequence(:name) {|n| "proofer#{n}"}
f.live true
end


Factory.define :device_type do |f|
f.sequence(:name) {|n| "device_type#{n}"}
f.live true
f.association :output_type
end


Here is the controller test:
test "should create device_type" do
output_type = Factory(:output_type)
@device_types_attr = Factory.attributes_for(:device_type)
assert_difference('DeviceType.count') do
post :create, :device_type => @device_types_attr
end

assert_redirected_to device_type_path(assigns(:device_type))
end



When I run the actual script through a browser and watch the log I get this
Parameters: {"commit"=>"Create", "device_type"=>{"name"=>"testLaser", "live"=>"1", "output_type_id"=>"2"},

But when I run the test, I get this
Parameters: {"device_type"=>{"name"=>"device_type1", "live"=>true}}

ie - no output type is being sent.

Why?
(hmmm - just noticed the live=>true and live=>'1'. Don't suppose that is the problem, but worth checking it out)

Wednesday 19 August 2009

It works, but I am not sure it is right. Seems very kludgy

have an organisation class, and organisations can be clients, suppliers, printers or prospects.
Want to be able to control this through a form - using check boxes.
The models etc are:
class Client <>
belongs_to :organisation


class Printer <>
belongs_to :organisation



class Organisation <>
has_one :printer
has_one :client


But have had a nightmare sorting out the controller for handling all of this. I am sure there is a better way of doing this.
def update
#get the org type ids
params[:organisation_type_ids] ||= []
#check to se if we have clients etc for those org types
debugger
client = Client.find_by_organisation_id(@organisation.id)
printer = Printer.find_by_organisation_id(@organisation.id)
if params[:organisation_type_ids].length > 0
params[:organisation_type_ids].each do |ot|
case ot.to_i
when 1:
if client.nil?
@organisation.create_client()
end
when 2:
if printer.nil?
@organisation.create_printer()
end
else
end
end
else #none are checked - so get rid of any that exist
if client
@organisation.client.destroy
end
if printer
@organisation.printer.destroy
end
end
#now get rid of any that have been unchecked
#ie client/printer exist but are not in params[:organisation_type_ids]

unless client.nil?
unless params[:organisation_type_ids].include?('1')
@organisation.client.destroy
end
end

unless printer.nil?
unless params[:organisation_type_ids].include?('2')
@organisation.printer.destroy
end
end

It seems the very opposite of DRY (is that wet?) and very, very kludgy. Sure it works, but I am sure that I am failing to understand the power of associations to do the heavy lifting for me.

Tuesday 18 August 2009

Why testing rocks - and ignore the last one

The polymorphic thing was a dead-end.
Cleared it all out - replaced it with a much more simple arrangement.
K.I.S.S. was never so true.

Love testing. make all the changes, run the test suite and ...

Started
..................................................................
Finished in 5.134175 seconds.

66 tests, 170 assertions, 0 failures, 0 errors

Polymorphic associations make my head hurt

Oh man.
I have an organisation class which has a number of "sub" classes - clients, printers, prospects, suppliers etc. An organisation can have many sub classes (ie an organisation could be simultaneously a client and a supplier for example).
Because clients, printers and prospects are quite different beasts they have to be different classes - not just different instances of the same class - hence the need to have a polymorphic relationship.
Tried to follow Ryan Bates's railscast but it wasn't really working for me.
After playing around with the console to get my head around what is really going on I came up with another way of sorting them out.
Have got the create method to work.
The way I came up with works on the basis that having denoted two classes to have a polymorphic relationship with each other, you can assign an instance of one to the other through the join (and that makes perfect sense ...)
What do I mean by that? Here are the models
class Organisation < ActiveRecord::Base
belongs_to :resource, :polymorphic => true

class Client < ActiveRecord::Base
has_one :organisation, :as => :resource

class Printer < ActiveRecord::Base
has_one :organisation, :as => :resource
if I instantiate an organisation object, o, and a client object, c, then by doing o.resource = c, I get the join I am looking for (sets the resource_id and resource_type) correctly.

My rather kludgy create model uses this:
params[:orgtypes].each do |ot|
@organisation = Organisation.new(params[:organisation])
resource = create_class(OrganisationType.find(ot).name)
resource.save!
@organisation.resource = resource


The create_class method takes a string and returns an instance of that class:
def create_class var
Object.const_get(var).new
end

I have a table of classes in the OrganisationType class - which allows me to add new ones dynamically which was my concern with doing everything hardwired - if I want a new sort of polymorphic thing, I can add one quite easily.
Now to sort out the update method, and to write some proper tests to make sure this sucker works in the way I hope it does.

Friday 14 August 2009

a sight for sore eyes

Started
................................................................
Finished in 3.983101 seconds.

64 tests, 166 assertions, 0 failures, 0 errors


Unit tests with Factory Girl

Getting the HABTM working was a tricky thing. In the end I had to do this:

def setup
@job = Factory.create(:job)
@version = Factory.build(:version, :job_id =>@job.id)
@printer_set_up = Factory.build(:printer_set_up)

3.times {
pf = Factory.create(:printer_format)
@printer_set_up.printer_formats << page_assembly =" Factory.create(:page_assembly," printer_id =""> @printer_set_up.printer_id, :job_id => @job.id)
end


PrinterFormat and PrinterSetUp both have HABTM relationships with each other.

Friday 31 July 2009

A little thing that saved me

Factory Girl stringify_keys error in Create Test.

Now have to work out why everything else is going wrong ... I think I have to work out how to stop other classes from screwing up the thing I am testing. Sounds like I need stubs and/or mocks. Just have to work out how to use them ...

Tuesday 28 July 2009

Rich list of cucumber tutorials etc

http://wiki.github.com/aslakhellesoy/cucumber/tutorials-and-related-blog-posts

redgreen not working

Could not get this bugger to work at all.
After much fiddling around - and a lot of googling, the penultimate comment on here solved it.
There was a lot of talk on sites about edit the .autotest file - but, er, on my install I had three .autotest files - which one to edit?
As it turns out, none of them. I had to make my own in the ~/ directory.

I am using SSH to remote into a RHEL5 box.
did a
$> vim ~/.autotest

got the usual vim type new file thing
and then typed

require 'redgreen/autotest'

yes - that way round, and NOT require 'autotest/redgreen'.
Save that (remembering not to hit Apple-S which sends Vim into a right old state) and at long last glorious living technicolour. Well, red and green at least - oh and amber too.
Second step on the journey of a thousand miles.

Having spent some time trawling around and looking at testing, and following the advice of the ever sagacious Ryan Bates, I think it is worth investing the time and effort in getting a solid test environment built.
To that end it looks like the following
Mocha
RSpec
Cucumber
Webrat
FactoryGirl.
It worries me that that is five packages to try and get working. However, I have got the Unit tests working pretty well so far using fixtures etc.
I think I am going to try and use FactoryGirl rather than fixtures. My brief foray into fixtures was not a happy one. They seem very brittle.

Monday 27 July 2009

Factory Girl

Wow - doesn't take long to get pissed off with fixtures, does it? They are incredibly brittle and I spent a load of time hacking fixtures to get them to pass the tests that I knew it would pass. Seemed like a pretty good waste of time.
Soooo - truffling around I found the excellent Ryan Bates had produced a very useful railscast on Factory Girl which seems - one functional test completed - to be a lot better.
I still want to get my head around cucumber and rspec - even shelling out a few bob to buy the book.
It seems very much the right way to go.

Friday 24 July 2009

test, test, test

Ok. Have managed (eventually) to get all the Unit tests to pass. That was a very illustrative experience and highlighted some issues - such as not getting all the associations completely nailed.
Funny how a quick "test" in the browser isn't really up to the job at all.
There are some issues with testing callbacks - doesn't seem anyway to pass information to and from the callback.

Now trying to crack the controller tests. The scaffold tests have, so far, failed in rather too many ways.
1) Failure:
test_should_create_brisque_set_up(BrisqueSetUpsControllerTest) [test/functional/brisque_set_ups_controller_test.rb:16]:
"BrisqueSetUp.count" didn't change by 1.
<3> expected but was
<2>.

2) Failure:
test_should_update_brisque_set_up(BrisqueSetUpsControllerTest) [test/functional/brisque_set_ups_controller_test.rb:35]:
Expected response to be a <:redirect>, but was <200>


Not quite sure why this should happen since this is an untouched-by-human-hands object.
We'll find out ...

Monday 29 June 2009

So far, so good

It is Mao's journey of a thousand miles, it begins with one step. So far, most problems have been resolved by throwing enough time and hard work at them.
The next problem - a recalcitrant radio button that refuses to pick up its value:


<%= f.label :verhorcut, "horizontal" %> <%= f.radio_button :verhorcut, 0 %>
<%= f.label :verhorcut, "vertical" %> <%= f.radio_button :verhorcut, 1 %>



there is a field called verhorcut - it is returning the correct value, but so far seem unable to pick up a value for it. In the schema it is a boolean so have tried "0", 0 and "false" but nothing so far.
Keep plodding away.

Next on the agenda - some proper unit testing.

Tuesday 23 June 2009

Everything comes to he who waits

Problem solved. It was behaving very oddly - as if the class didn't really exist properly. Rebuilt the controller and now all works. Hurrah.

Next problem.
Have three classes:
class StoredFile < ActiveRecord::Base
belongs_to :job_store_path
belongs_to :job_set_up
accepts_nested_attributes_for :job_store_path, :allow_destroy => true

class JobSetUp < ActiveRecord::Base
has_many :stored_files
has_many :job_store_paths, :through => :stored_files
accepts_nested_attributes_for :stored_files, :allow_destroy => true
accepts_nested_attributes_for :job_store_paths, :allow_destroy => true

class JobStorePath < ActiveRecord::Base
has_many :stored_files
has_many :job_set_ups, :through => :stored_files

The idea is to generate suggested path names for files, but then store the actual path name so that should the structure change, the old files are not going to be lost.
This works fine:
<% @job_set_up.stored_files.each do |stored_file| %>
<%= content_tag(:strong, stored_file.job_store_path_id) %>
<%=stored_file.address %>

<% end %>

But what I really want is:
stored_file.job_store_path.name - but if I do this I get:

NoMethodError in Job_set_ups#show

Showing app/views/job_set_ups/show.html.erb where line #11 raised:

You have a nil object when you didn't expect it!
The error occurred while evaluating nil.name


Ho hum.

Learning a new language

One of the things I hate most about this is how slooowwwwwwww it is. You know you are going to get there, but boy does it take time.
RoR is proving to be a tricky beast. All that is great about it is also all that is bad. The abstraction is great when it works, but when it doesn't - grrrr.
Having cut my teeth on PHP and writing SQL statements it is so frustrating knowing that you know how to do what you want, but getting the RoR framework to do your bidding is the devil's own business.
Still we will get there.

Currently still grasping at associations. Everytime I think I have got them grasped, they slip through your fingers.
Grappling with a "
NameError in Stored filesController#index
uninitialized constant StoredFilesController::StoredFiles"

But we'll get there. Have to say loving the console - being able to try stuff out before you buy - lovely.