Showing posts with label Fixtures. Show all posts
Showing posts with label Fixtures. Show all posts

Monday, May 29, 2006

Beautify Fixtures (Ruby on Rails)

After generating fixtures from my development database (you can read about it here) I decided to make them nice.

Up to now, for example, Permissions were labelled permission_001 and so on. And that is quite counter-intuitive. A good convention to label permissions would be controller_action. For example:

user_new: 
action: new 
id: 19 
controller: user 

The same applies to roles (you can label them with their name) and permissions_roles (you can build the name from their associated role and permission names). This is what my small script does. It is a rake task.
desc "Labels Roles, Permissions and PermissionsRoles after their value so that
the fixture becomes more readable. You can specify the DIR where fixtures we want to modify are.

require 'yaml' 
class Hash 
    def find_item(key, value, default=nil) 
        each do |k, v| 
            return k if (v[key] == value) || (v[key] == value.to_i) 
        end 
        default 
    end 
end 

task :beautify_fixtures => :environment do 
    dir = ENV['DIR'] || "#{RAILS_ROOT}/test/fixtures" 
    db   = ENV['DB']   || 'development' 
    File.cp "#{dir}/roles.yml",             "#{dir}/roles.bkp.yml" 
    File.cp "#{dir}/permissions.yml",       "#{dir}/permissions.bkp.yml" 
    File.cp "#{dir}/permissions_roles.yml", "#{dir}/permissions_roles.bkp.yml" 
    permissions = YAML.load_file("#{dir}/permissions.bkp.yml") 
    roles = YAML.load_file("#{dir}/roles.bkp.yml") 
    File.open("#{dir}/permissions.yml", 'w') do |file| 
        permissions.each do |k, v| 
            controller = v['controller'] 
            action = v['action'] 
            file.write "#{controller}_#{action}:n" 
            v.each {|key, value| file.write "  #{key}: #{value}n"} 
        end 
    end 
    File.open("#{dir}/roles.yml", 'w') do |file| 
        roles.each do |k, record| 
            file.write "#{record['name'].downcase}:n" 
            record.each {|key, value| file.write "  #{key}: #{value}n"} 
        end 
    end 

    permissions = YAML.load_file("#{dir}/permissions.yml") 
    roles = YAML.load_file("#{dir}/roles.yml") 
    prs = YAML.load_file("#{dir}/permissions_roles.bkp.yml") 
    
    File.open("#{dir}/permissions_roles.yml", 'w') do |file| 
        prs.each do |k, record| 
            permission = permissions.find_item('id', record['permission_id']) 
            role = roles.find_item('id', record['role_id']) 
            file.write "#{role}_#{permission}n" 
            record.each {|key, value| file.write "  #{key}: #{value}n"} 
        end 
    end 
end 

You can find a downloadable version here [BROKEN!]

Friday, May 26, 2006

Dump db to fixtures (generate fixtures from db)

This is a quite interesting thread on rails ml with the solution to my problem.
I wanted to generate fixtures automatically from my db. This is a rake action that does the job well. Just put it into lib/tasks/ and call it dump_fixtures.rake

desc 'Dump a database to yaml fixtures. Set environment variables DB
and DEST to specify the target database and destination path for the
fixtures. DB defaults to development and DEST defaults to RAILS_ROOT/
test/fixtures.'

task :dump_fixtures => :environment do
    path = ENV['DEST'] || "#{RAILS_ROOT}/test/fixtures"
    db   = ENV['DB']   || 'development'
    sql  = 'SELECT * FROM %s'

    ActiveRecord::Base.establish_connection(db)
    ActiveRecord::Base.connection.select_values('show tables').each do |table_name|
        i = '000'
        File.open("#{path}/#{table_name}.yml", 'wb') do |file|
            file.write ActiveRecord::Base.connection.select_all(sql %
table_name).inject({}) { |hash, record|
                hash["#{table_name}_#{i.succ!}"] = record
                hash
            }.to_yaml
        end
    end
end
# ActiveRecord::Base.connection.select_values('show tables')
# is mysql specific
# SQLite:  ActiveRecord::Base.connection.select_values('.table')
# Postgres
# table_names = ActiveRecord::Base.connection.select_values(<<-end_sql)
#    SELECT c.relname
#    FROM pg_class c
#      LEFT JOIN pg_roles r     ON r.oid = c.relowner
#      LEFT JOIN pg_namespace n ON n.oid = c.relnamespace
#    WHERE c.relkind IN ('r','')
#      AND n.nspname IN ('myappschema', 'public')
#      AND pg_table_is_visible(c.oid)
# end_sql