Caches.rb Documentation 0

Posted by yrashk

I’ve wrote a short introductory to Caches.rb

Basecamp Clones? 2

Posted by yrashk

Somebody is requesting a bid for a Basecamp clone :)

RubyOnRails:: Constancy Snippet 0

Posted by yrashk

A small snippet that allows to validate attribute constancy. May be it could be implemented even easily?

1
2
3
4
5
6
7
8
9
module ActiveRecord::Validations::ClassMethods

        def validates_constancy_of(*attr)
                validates_each attr, :on => :update do |record,attr,value|
                        record.errors.add attr, 'could not be modified' unless value == find(record.id).send(attr)
                end
        end

end

Rails: Composite Versioned Entities 0

Posted by yrashk

In one of the projects I’m working on now I had a need in a composite versioned entities. That means that I have an acts_as_versioned entity (let us call it Person) which has_many other entities (say, Accounts) that needs to be versioned in sync with Person versions, so, Person #1 has Accounts #1,#2, Person #2 has Accounts #2,#3, etc.

I’ve tried to hack with acts_as_versioned_association plugin but I have failed.

So here you are some kind of an extraction from what I have done. It is by no way

  • the best way to solve this problem
  • error-free

Also, may be I was just missing something important (it’s easy for a long night coding session) to accomplish it easier.

First, I’ve said that Person version should be updated on each save:


        acts_as_versioned :if => lambda { true }

It isn’t very good idea, I think it is better to track has_many :accounts changes or something like this, and I surely will do this later and update this entry.

Then, I’ve added versioned class changes in person.rb:

1
2
3
Person.versioned_class.class_eval do
        has_many :accounts, :foreign_key => 'person_version_id'
end

Back to Person, I’ve added accounts method, with is a proxy to current version’s accounts.

1
2
3
        def accounts(force = false)
                find_version(version).accounts(force)
        end

Then, to allow each new version has the same accounts like previous version had, I’ve specified Person to copy them after each update:

1
2
3
        def after_update
                versions(true)[-2].accounts(true).each { |account| accounts << account }
        end

Finally, I’ve added versions support in an account.rb:

1
2
3
4
class Account < ActiveRecord::Base
        belongs_to :person
        belongs_to :person_version, :class_name => "Person::Version", :foreign_key => "person_version_id"
end

(don’t forget to add_column :accounts, :person_version_id, :integer)

That seems to be everything I needed to solve my problem. Unfortunately, I haven’t a chance to double check it yet (my specification tests only what I needed exactly) and the example presented here wasn’t actually tested (I had another entities and more complicated relationships between them). So, if you will find a mistake or any kind of problem with this snippet, please let me know.

Thank you.

Rubyforge and (at least) Gems 0

Posted by yrashk

IRC quote as a preface:

Yurik: is rubyforge down again?
[10:01pm] JasonBoxatWork: Yurik: Rubyforge is up sometimes?

May be it could be a good solution to run a community-donated S3 gem server? AFAIR, it’s quite a high availability service, and it shouldn’t be very hard to develop a gem distribution system on top of it?

Rails: Model Specification: Done 0

Posted by yrashk

I’ve moved my model specifications (like belongs_to, has_many, validates_ and friends) to RSpec specifications.

This was not very complicated. I admit that it is an early implementation with certain problems.

Please do not use this for anything except experiments. This solutions causes few problems that I haven’t fixed yet

Anyway, let me try to explain what I’ve done.

I rewrote spec/spec_helper.rb:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
ENV["RAILS_ENV"] ||= "test"

case ENV['RAILS_ENV']
when 'test'
        require File.expand_path(File.dirname(__FILE__) + "/../config/environment")
        require 'controller_mixin'
        require 'rspec_on_rails'

        class SpecTestCase < Test::Unit::TestCase
                self.use_transactional_fixtures = true
                self.use_instantiated_fixtures  = false
                self.fixture_path = RAILS_ROOT + '/spec/fixtures'

                # You can set up your global fixtures here, or you
                # can do it in individual contexts
                #fixtures :table_a, :table_b

                def run(*args)
                end

                def setup
                        super
                end

                def teardown
                        super
                end
        end

        module Spec
                module Runner
                        class Context
                                def before_context_eval
                                        inherit SpecTestCase
                                end
                        end
                end
        end

        Test::Unit.run = true
else
        class << self
                def context(name,&block) ; end
        end
end        

Then, I’ve created has_specification (I have this script in lib/):

1
2
3
4
5
6
7
module ActiveRecord::Specification
        def has_specification
                unless ENV['RAILS_ENV'] == 'test'
                        require File.dirname(__FILE__)+"/../spec/models/#{self.to_s.tableize.singularize}_spec"
                end
        end
end

and surely added it to ActiveRecord::Base:


ActiveRecord::Base.extend ActiveRecord::Specification

Now, I was able to move all my specifications to spec/models/model_spec.rb. I did it by just adding something like

1
2
3
class Model < ActiveRecord::Base
 has_many :ideas
end

before specification contexts.

And, finally, I’ve replaced that specifications for app/models/model.rb with has_specification:

1
2
3
class Model < ActiveRecord::Base
 has_specification
end

It seems that it’s all.

I’m sure it could be done much better. But it’s a first quick hack solution to probe the idea, so please don’t beat me.

Was it a good idea at all? :)

Rails: Model Specification 0

Posted by yrashk

I enjoy Rspec for Rails . It definitely saves my time, money and nerves.

But I have found that I want some parts of ActiveRecords to migrate to specifications. I mean those validates, belongs_to, has_many, caches and friends. They are so specification-like!

I will definitely try to find a best way to accomplish this idea, and if I’ll find something interesting, I’ll update my blog on this.

Rails: Migrations: AddSWIFTCodes Workaround 0

Posted by yrashk

If I’m not missing something, there is a minor bug in Rails (and in Edge Rails, too) that does not allow you to specify migrations files like add_swift_codes.rb with AddSWIFTCodes class inside; it will raise an error.

dev.rubyonrails.org seems to run of out of hard drive capacity, so here you are a very quick workaround:

1
2
3
4
5
6
7
8
9
class ActiveRecord::Migrator
        def migration_class(migration_name)
                begin
                        migration_name.camelize.constantize
                rescue
                        Object.constants.grep(Regexp.new(migration_name.camelize,"i")).first.constantize
                end
        end
end

I’m not sure it is a best solution, but it seems that it works for me right now. I’ll try to write down a patch for Edge Rails + test soon.