MoneyBird - The Rails Side
-
Upload
edwin-vlieg -
Category
Technology
-
view
1.240 -
download
1
description
Transcript of MoneyBird - The Rails Side
The Rails side!Edwin Vlieg - BlueTools
Twente.rb - november 2008
Edwin Vlieg — MoneyBird 2008
MoneyBird
• Simpele facturatie voor kleine bedrijven
• Facturen aanmaken, versturen en beheren
• Simpel contactbeheer
• Binnenkort periodieke facturen
• Innovatieve Ajax interface voor factuur bewerken
2
Edwin Vlieg — MoneyBird 2008
MoneyBird
• April 2008: eerste idee
• Juni 2008: prototypes van applicatie gereed (HTML mockups met JavaScript functionaliteit)
• September 2008: test versie gereed
• Oktober 2008: live!
3
Edwin Vlieg — MoneyBird 2008
The Rails side!+‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐+‐‐‐‐‐‐‐+‐‐‐‐‐‐‐+‐‐‐‐‐‐‐‐‐+‐‐‐‐‐‐‐‐‐+‐‐‐‐‐+‐‐‐‐‐‐‐+| Name | Lines | LOC | Classes | Methods | M/C | LOC/M |+‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐+‐‐‐‐‐‐‐+‐‐‐‐‐‐‐+‐‐‐‐‐‐‐‐‐+‐‐‐‐‐‐‐‐‐+‐‐‐‐‐+‐‐‐‐‐‐‐+| Controllers | 977 | 779 | 10 | 89 | 8 | 6 || Helpers | 300 | 194 | 0 | 30 | 0 | 4 || Models | 1340 | 983 | 22 | 127 | 5 | 5 || Libraries | 830 | 575 | 4 | 61 | 15 | 7 || Model specs | 1045 | 826 | 0 | 3 | 0 | 273 || View specs | 252 | 189 | 0 | 0 | 0 | 0 || Controller specs | 678 | 560 | 1 | 6 | 6 | 91 || Helper specs | 185 | 162 | 0 | 0 | 0 | 0 || Library specs | 68 | 57 | 1 | 0 | 0 | 0 |+‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐+‐‐‐‐‐‐‐+‐‐‐‐‐‐‐+‐‐‐‐‐‐‐‐‐+‐‐‐‐‐‐‐‐‐+‐‐‐‐‐+‐‐‐‐‐‐‐+| Total | 5675 | 4325 | 38 | 316 | 8 | 11 |+‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐+‐‐‐‐‐‐‐+‐‐‐‐‐‐‐+‐‐‐‐‐‐‐‐‐+‐‐‐‐‐‐‐‐‐+‐‐‐‐‐+‐‐‐‐‐‐‐+ Code LOC: 2531 Test LOC: 1794 Code to Test Ratio: 1:0.7
4
Edwin Vlieg — MoneyBird 2008
The Rails side!
• Rails 2.2 (since this week!)
• PostgreSQL
• Capistrano
• Developed in TextMate
5
Edwin Vlieg — MoneyBird 2008
Plugins
• acts_as_state_machine
• attachment_fu
• i18n_labels
• localized_dates
• subdomain_fu
• restful-authentication
6
Edwin Vlieg — MoneyBird 2008
Rails 2.2: I18n
• Scoping
# Override translate method to consider translate_scope. def t(text, options = {}) scope = (translate_scope.dup << options.delete(:subscope)).compact super(text, {:scope => scope}.merge(options)) end
# The current translation scope, default to current controller name. def translate_scope @translate_scope || [template.base_path] end
7
Edwin Vlieg — MoneyBird 2008
Rails 2.2: I18n
• Localized labels, based on ActiveRecord::human_attribute_name
<tr> <th><%= f.label :name %></label></th> <td> <%= f.text_field :name %> <%= error_message_on :contact, :name %> </td> </tr> <tr> <th><%= f.label :contact_name %></th> <td><%= f.text_field :contact_name %></td> </tr>
8
Edwin Vlieg — MoneyBird 2008
Rails 2.2: I18n
• In locales definition:
nl: activerecord: attributes: contact: contact_name: Contactpersoon name: Naam of Bedrijfsnaam
9
Edwin Vlieg — MoneyBird 2008
Testing• RSpec
• For testing models (business logic)
• Covers 141 examples
• Cucumber
• Plain text stories for integration testing
• Covers 535 steps
• Factory girl
• Webrat10
Edwin Vlieg — MoneyBird 2008
Testing: CucumberFeature: invoice An user should be able to manage his invoices Scenario: Create a new invoice Given I'm logged in as edwin at bluetools When I follow "New invoice" And I fill in "Name or Companyname" with "Test company" And I fill in "Address" with "Hengelosestraat 534" And I fill in "invoice_zipcode" with "7500AG" And I fill in "invoice_city" with "Enschede" And I fill in "invoice_new_detail_attributes__description" with "Test description" And I fill in "invoice_new_detail_attributes__price" with "123" And I press "Save" Then an invoice with invoice id "2008-0001" should exist And I should see "2008-0001" And I should see "Test company" And I should see "Test description" Scenario: Create a new invoice with no invoice details Given I'm logged in as edwin at bluetools When I follow "New invoice" And I fill in "Name or Companyname" with "Test company" And I fill in "Address" with "Hengelosestraat 534" And I fill in "invoice_zipcode" with "7500AG" And I fill in "invoice_city" with "Enschede" And I press "Save" Then no invoice with name "Test company" should exist And I should see "Details should contain at least one row"
11
Edwin Vlieg — MoneyBird 2008
Testing: Cucumber
• Only ~30 steps defined!
• Example resource definition and assertion:Given /^I've created (a|an) ([A-z].*) with ([A-z ].* ".*"( and )?)+$/ do |_, resource, fields, _| #' fields = fields.split(" and ").collect { |f| r = f.strip.match(/^([A-z ].*) "(.*)"$/); [r[1].tr(" ", "_").underscore, r[2]] }.flatten Factory(resource.tr(" ", "_").to_sym, Hash[*fields])end
# Then a company with name "foobar" should existThen /^(a|an|no) ([A-z].*) with ([A-z ].*) "(.*)" should exist$/ do |condition, resource, field, value| if resource.to_class.respond_to?(:exists?) condition = condition == 'no' ? false : true resource.to_class.exists?({ field.tr(" ", "_").underscore => value }).should == condition else raise "Resource #{resource.classify} isn't a model" endend
12
Edwin Vlieg — MoneyBird 2008
PDF generation
• PDF writer:
• API.... :-(
• PNG file errors (‘PNG uses more than 8 bits’, ‘Invalid filter algorithm 61’)
13
Edwin Vlieg — MoneyBird 2008
PDF generation
• Prawn
• API... :-)
• Better PNG support
• Only the Euro sign doesn’t show up
14
Edwin Vlieg — MoneyBird 2008
PDF generationPrawn::Document.generate("fancy_table.pdf") do
data = [["Gregory Brown", "[email protected]" ], ["James Healy" , "[email protected]" ], ["Ross Perot" , "[email protected]" ], ["Al Gore" , "[email protected]" ], ["Ralph Nader" , "[email protected]" ]]
table data, :position => :center, :headers => ["Name", "Email"], :row_colors => ["ffffff","ffff00"], :vertical_padding => 5, :horizontal_padding => 3end
15
Edwin Vlieg — MoneyBird 2008
Concerned_with
• Problem: Invoice model has 450 LOC
• Other models have on average 200 LOC
• Make the model less fat with concerned_with
16
Edwin Vlieg — MoneyBird 2008
Concerned_with# In config/initializersclass << ActiveRecord::Base def concerned_with(*concerns) concerns.each do |concern| require_dependency "#{name.underscore}/#{concern}" end endend
# In models/invoice.rbclass Invoice < ActiveRecord::Base concerned_with :validations, :states, :policies, :scopes ...end
# In models/invoice/validations.rbclass Invoice validates_presence_of ...end
17
Edwin Vlieg — MoneyBird 2008
Invoice edit interface
• Difference between new and edit action:
• ‘edit’ is performed on an persistant instance
• ‘new’ does not exist after the request has finished
18
Edwin Vlieg — MoneyBird 2008
Invoice edit interface
• Solution: always load the complete form on the background
• Switch between display and form with JS
• Just plain old submitting the complete form for creating a new record
19
Edwin Vlieg — MoneyBird 2008
Invoice edit interface
• Input is validated and rendered via an Ajax call.
<div id="invoice_description"> <div class="show"> <%= render :partial => "invoice_description" %> </div> <div class="form"> <%= render :partial => "invoice_description_form" %> </div> </div>
20
The End!Try MoneyBird for free at www.moneybird.nl