Rails says, "Missing pdf-writer" when pdf-writer is unpacked in vendor/gems
Issue:
*"Missing these required gems: pdf-writer = 1.1.8"*
config/environment.rb:
Issue:
*"Missing these required gems: pdf-writer = 1.1.8"*
config/environment.rb:
That looks write... what's the issue? Turns out my new server didn't have the required dependencies.
I added this above the config/gem line:
and saw:
the fixes:
remove the require line, and voila!
*"Missing these required gems: pdf-writer = 1.1.8"*
config/environment.rb:
Issue:
*"Missing these required gems: pdf-writer = 1.1.8"*
config/environment.rb:
1 |
config.gem "pdf-writer", :lib => "pdf/writer", :version => '1.1.8' |
That looks write... what's the issue? Turns out my new server didn't have the required dependencies.
I added this above the config/gem line:
1 |
require "#{RAILS_ROOT}/vendor/gems/pdf-writer-1.1.8/lib/pdf/writer.rb"
|
and saw:
1 2 |
no such file to load -- color no such file to load -- transaction-simple # after fixing color |
the fixes:
1 2 |
gem install color gem install transaction-simple |
remove the require line, and voila!
Anthenticating against PayFlowPro for Rails with ActiveMerchant
Rails is fortunate to have ActiveMerchant, a gem that provides a standard interface for billing. Unfortunately, there are a wide variety of gateways out there and each has their own "uniqueness." I experienced PayFlowPro's "uniqueness" today and thought I would share my now-working spike code.
THE PARTNER FIELD
The partner field below is optional. If you leave it blank, the default will be PayPal. The other option, apparently, is VeriSign. I have included it here because magical, undocumented parameters confuse people.
MERCHANT LOGIN
in my case, this was the company name without any spaces. It's the same as the merchant login required to log in to the PayflowPro website.
MOVING FROM A SPIKE TO REAL CODE
Copy the above code, replace your company name, and get that to say "Accepted"... once that's done, check back for my blog entry on the easiest way to set up ActiveMerchant in a Rails app.
ISSUES I EXPERIENCED
PayFlowPro response 26 - Invalid Vendor Account
I was using my username where my merchant login should have been.
PayflowPro response 1 - User authentication failed
Here I was submitting the company name as my :login but was not including my username under :user
REFERENCES
com.googlegroups.activemerchant - Payflow Pro Integration
Payflow Gateway - User authentication failed
THE PARTNER FIELD
The partner field below is optional. If you leave it blank, the default will be PayPal. The other option, apparently, is VeriSign. I have included it here because magical, undocumented parameters confuse people.
MERCHANT LOGIN
in my case, this was the company name without any spaces. It's the same as the merchant login required to log in to the PayflowPro website.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 |
gateway = ActiveMerchant::Billing::PayflowGateway.new( :login => 'my_company_name', # 'Merchant Login from the login page :user => 'my_username', :password => 'ComPliCatedP4sSw0rd', :partner => 'PayPal' ) credit_card = ActiveMerchant::Billing::CreditCard.new( :number => '5105105105105100', :month => '9', :year => '2011', :first_name => 'Longbob', :last_name => 'Longsen', :verification_value => '123', :type => 'master' ) # Make a $1 purchase (100 cents) response = gateway.purchase(100, credit_card) puts response.success? puts response.message |
MOVING FROM A SPIKE TO REAL CODE
Copy the above code, replace your company name, and get that to say "Accepted"... once that's done, check back for my blog entry on the easiest way to set up ActiveMerchant in a Rails app.
ISSUES I EXPERIENCED
PayFlowPro response 26 - Invalid Vendor Account
I was using my username where my merchant login should have been.
PayflowPro response 1 - User authentication failed
Here I was submitting the company name as my :login but was not including my username under :user
REFERENCES
com.googlegroups.activemerchant - Payflow Pro Integration
Payflow Gateway - User authentication failed
Triangles and Chat Bubbles with pure CSS
This is pretty awesome.
http://www.dinnermint.org/css/creating-triangles-in-css/comment-page-2/#comment-313
Now if only it worked in IE. :(
http://www.dinnermint.org/css/creating-triangles-in-css/comment-page-2/#comment-313
Now if only it worked in IE. :(
Automated Testing for Infrastrure
I have a client whose website is subject to HIPAA regulations. I just finished setting up SSL for them. I also set up redirects so that:
http://domain.com => https://www.domain.com
http://www.domain.com => https://www.domain.com
It all works now. Unfortunately, I've become accustomed to the feeling of security that I get from automated tests. I can't use rspec here, because that configuration is on the server. I have signed up for monitoring service, but that won't tell me if somehow https://www.domain.com starts serving insecure pages. (most modern browsers will flip, but that doesn't get me around HIPAA.) What if the server crashes, has to be rebuilt, and I forget to set up the SSL stuff? It could be weeks before someone discovers that it isn't there, and that isn't good enough.
Not sure yet what to do.
http://domain.com => https://www.domain.com
http://www.domain.com => https://www.domain.com
It all works now. Unfortunately, I've become accustomed to the feeling of security that I get from automated tests. I can't use rspec here, because that configuration is on the server. I have signed up for monitoring service, but that won't tell me if somehow https://www.domain.com starts serving insecure pages. (most modern browsers will flip, but that doesn't get me around HIPAA.) What if the server crashes, has to be rebuilt, and I forget to set up the SSL stuff? It could be weeks before someone discovers that it isn't there, and that isn't good enough.
Not sure yet what to do.
HTML5 GeoLocation Accuracy
I spent some time looking in to HTML5 features this morning. The first one on the list is GeoLocation. This demo gave a position within a block of my house:
http://html5demos.com/geo
Interestingly, when I went to visit the page again, it located me within feet of my previous house, more than 500 miles away. According to the Chrome GeoLocation notes, it uses data including wireless networks to find your location, so I assume Google located my wireless router both places.
http://html5demos.com/geo
Interestingly, when I went to visit the page again, it located me within feet of my previous house, more than 500 miles away. According to the Chrome GeoLocation notes, it uses data including wireless networks to find your location, so I assume Google located my wireless router both places.
validates_uniqueness_of results in " undefined method `text?' for nil:NilClass "
I had the following model:
I changed :visit_type to :visit_type_id and it went away.
1 2 3 4 5 6 7 8 9 10 11 12 |
class Visit < ActiveRecord::Base belongs_to :visit_type belongs_to :patient validates_presence_of :visit_type validates_presence_of :patient validates_presence_of :date validates_uniqueness_of :visit_type end |
I changed :visit_type to :visit_type_id and it went away.
Web Dev Tools - Color Scheme Designer
Color Scheme Designer
colorschemedesigner.com
As any of my clients will tell you, my design skill falls somewhere between "enh" and "meh." Fortunately, someone smarter than me has found some math that can help. I use this tool to find colors that match the existing colors. Once I've found a set of colors that look good, I can bookmark the color scheme in a folder for that client, and reference it whenever I need to look at their color scheme.
Another great, free tool!
colorschemedesigner.com
As any of my clients will tell you, my design skill falls somewhere between "enh" and "meh." Fortunately, someone smarter than me has found some math that can help. I use this tool to find colors that match the existing colors. Once I've found a set of colors that look good, I can bookmark the color scheme in a folder for that client, and reference it whenever I need to look at their color scheme.
Another great, free tool!
MySQL says " Incorrect column specifier for column 'x' "
My rails app uses a database of dubious origin, so I wasn't shocked when I had issues. Because I imported the database from sql, I first noticed the issue when running tests. Tests start with
rake db:test:clone
which starts by regenerating db/schema.rb using
rake db:schema:dump
My db/schema.rb then contained columns like this:
table.float :somefloat :limit => 255
I'm pretty sure you can't have a limit without a precision and scale... in my case, I created this migration:
alter_column :table, :field, :decimal
and everything was golden.
rake db:test:clone
which starts by regenerating db/schema.rb using
rake db:schema:dump
My db/schema.rb then contained columns like this:
table.float :somefloat :limit => 255
I'm pretty sure you can't have a limit without a precision and scale... in my case, I created this migration:
alter_column :table, :field, :decimal
and everything was golden.
users and profiles
I find myself, yet again^n, considering users and profiles.
Say you have the following models:
- User
- Doctor
- Patient
Of course, the concept of user is not the same as the concept of a person. User might be more accurately called Login, since it could be a bot or a guest login used by 100 various anonymous people.
your views have access to current_user. We'll make our lives easier by ssuming that current_user is always populated with a valid user.
What I remember thinking last time I was in this bruhaha was that a user could have one or more profiles. That's what we conveniently have here. A user can be a doctor, and if so, they have a doctor profile... license number, type of practice, whatever. That same person could be a patient. If so, we'll have information like... emergency contact, last_check_up, allergies.
So you can ask whether a user can see a patient. And obviously this falls under the User model since it's all about authentication and authorization.
ok... so now I want to welcome this user. If they are a doctor, I want to prepend their name with "Dr." first_name and last_name are on User.
ok great. At some point I'm running through a list of doctors and I'll want to output their names.
(a) we've already said that a user isn't necessarily a doctor; could be a group.
(b) for this app, there's no guarantee a doctor even has a login.
I don't want to store first_name, last_name twice... so that leads me to the conclusion that I need a Person model.
Person
first_name
last_name
dob
blah
So then we get:
Doctor#person_id
Patient#person_id
User#person_id ????
maybe, instead of that...
Person#user_id
so then
ok this seems very sensible.
Say you have the following models:
- User
- Doctor
- Patient
Of course, the concept of user is not the same as the concept of a person. User might be more accurately called Login, since it could be a bot or a guest login used by 100 various anonymous people.
your views have access to current_user. We'll make our lives easier by ssuming that current_user is always populated with a valid user.
What I remember thinking last time I was in this bruhaha was that a user could have one or more profiles. That's what we conveniently have here. A user can be a doctor, and if so, they have a doctor profile... license number, type of practice, whatever. That same person could be a patient. If so, we'll have information like... emergency contact, last_check_up, allergies.
So you can ask whether a user can see a patient. And obviously this falls under the User model since it's all about authentication and authorization.
1 2 3 4 5 6 7 |
class User def can_view?( patient ) (self == patient ) || (self.doctor && patient.doctor == self.doctor) end end |
ok... so now I want to welcome this user. If they are a doctor, I want to prepend their name with "Dr." first_name and last_name are on User.
1 2 3 4 5 6 |
class User def fullname [title, first_name, last_name].join(' ') end end - |
ok great. At some point I'm running through a list of doctors and I'll want to output their names.
1 2 3 4 5 |
class Doctor def to_s self.user.to_s end end |
(a) we've already said that a user isn't necessarily a doctor; could be a group.
(b) for this app, there's no guarantee a doctor even has a login.
I don't want to store first_name, last_name twice... so that leads me to the conclusion that I need a Person model.
Person
first_name
last_name
dob
blah
So then we get:
Doctor#person_id
Patient#person_id
User#person_id ????
maybe, instead of that...
Person#user_id
so then
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
class User def to_s person.to_s end end class Person def to_s title, first_name, last_name end end class Doctor def to_s person.to_s end end # same for patient |
ok this seems very sensible.
Why Ruby Complains about Nested Parentheses
Every time a dev asks me why Ruby doesn't like nested arguments without parens, I draw a blank, but I swear that it's an issue.
Here's an example of the issue:
it seems really obvious right now. I'm not sure why I can't think of that when it's clinch time. Anyway, this can be the obviously intended call:
or the unfortunate( and invalid, since h takes 1 not 2 arguments )
Here's an example of the issue:
1 |
=link_to h @person.philosophy, @person.philosophy |
it seems really obvious right now. I'm not sure why I can't think of that when it's clinch time. Anyway, this can be the obviously intended call:
1 |
=link_to( h( @person.philosophy ), @person.philosophy ) |
or the unfortunate( and invalid, since h takes 1 not 2 arguments )
1 |
=link_to( h( @person.philosophy, @person.philosophy )) |
changing an agile ticket with user story and acceptance criteria from a traditional ticket
This is a real-life example of a ticket write by a client that I converted into an "agile" user story with acceptance criteria, provided for those who want to find out whether there would be value for them in transitioning and those who want to understand the differences between them.
first step: user story
add acceptance criteria using [given/]when/then format
1 2 3 |
Title: Users can create a category from the Add Item screen The category drop down will contain a new item called "Add a New Category". When this option is selected a new text field will appear to give the category a name and possibly to select an icon. |
first step: user story
1 2 |
|
add acceptance criteria using [given/]when/then format
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 |
|
dd_roundies fails for AJAX with IE8
Rounding things in IE8 is one of the biggest farses ever.
After some research, I'm using dd_roundies. I won't explain how it works, because you don't deserve that kind of suffering. It seems to work for rounding objects in IE before the page is set to the "ready" state, but it's failing for me in ajax requests (and in fact any javascript that happens after the page hits the "ready" state.)
I found this bit in the code:
I already had the round method (below) to use jquery for rounding when that was an option, and roundies otherwise. I wasn't able to find a way to get IE to toggle the ready state of the document on ajax calls, so I created a method trigger_late_rounding( ).
I'll be replacing BrowserDetect with DD_roundies.IEwhatever as soon as I get around to it.
In your ajax .js, just...
ugly but effective.
It would be better to have patched dd_roundies, but it's not on github or ... whatever... if dd_roundies is still being maintained and you know where it lives, shoot me a note.
After some research, I'm using dd_roundies. I won't explain how it works, because you don't deserve that kind of suffering. It seems to work for rounding objects in IE before the page is set to the "ready" state, but it's failing for me in ajax requests (and in fact any javascript that happens after the page hits the "ready" state.)
I found this bit in the code:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 |
if (DD_roundies.IE8 && document.attachEvent && DD_roundies.querySelector) { document.attachEvent('onreadystatechange', function() { if (document.readyState == 'complete') { var selectors = DD_roundies.selectorsToProcess; var length = selectors.length; var delayedCall = function(node, radii, index) { setTimeout(function() { DD_roundies.roundify.call(node, radii); }, index*100); }; for (var i=0; i<length; i++) { var results = document.querySelectorAll(selectors[i].selector); var rLength = results.length; for (var r=0; r<rLength; r++) { if (results[r].nodeName != 'INPUT') { /* IE8 doesn't like to do this to inputs yet */ delayedCall(results[r], selectors[i].radii, r); } } } } }); } |
I already had the round method (below) to use jquery for rounding when that was an option, and roundies otherwise. I wasn't able to find a way to get IE to toggle the ready state of the document on ajax calls, so I created a method trigger_late_rounding( ).
I'll be replacing BrowserDetect with DD_roundies.IEwhatever as soon as I get around to it.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 |
function round( selector, radius ) { if( radius == null ) { radius = "10px"; } if( BrowserDetect.browser == 'Explorer' ) { DD_roundies.addRule(selector, radius); } else { $(function(){ $(selector).corner(radius); }); } } function trigger_late_rounding() { var selectors = DD_roundies.selectorsToProcess; var length = selectors.length; |
In your ajax .js, just...
1 2 |
round('.popup', '10px'); trigger_late_rendering(); |
ugly but effective.
It would be better to have patched dd_roundies, but it's not on github or ... whatever... if dd_roundies is still being maintained and you know where it lives, shoot me a note.
Getting started generating PDFs with Prince
Download and uncompress Prince:
Based on the documentation
jw@gallifrey:~/prince-7.1-linux$ prince http://app.local/reports/my_report.html -o /code/client/app/public/sample.pdf
IT WORKS! but it's kinda ugly.
add pdf.css based on the boom microformat ...
add .cover-page, .chapter, .cover-notes, etc
jw@gallifrey:~/prince-7.1-linux$ prince http://app.local/reports/my_report.html -s http://app.local/stylesheets/pdf.css -o /code/client/app/public/sample.pdf
jw@gallifrey:~$
jw@gallifrey:~$ sudo gem install princely
Successfully installed princely-1.2.5
1 gem installed
---
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 |
jw@gallifrey:~$ curl http://www.princexml.com/download/prince-7.1-linux.tar.gz -o prince.tar.gz
% Total % Received % Xferd Average Speed Time Time Time Current
Dload Upload Total Spent Left Speed
100 3879k 100 3879k 0 0 763k 0 0:00:05 0:00:05 --:--:-- 940k
jw@gallifrey:~$ tar -xzf prince.tar.gz
jw@gallifrey:~$ cd prince-7.1-linux/
jw@gallifrey:~/prince-7.1-linux$ ls
jw@gallifrey:~/prince-7.1-linux$ install.sh lib LICENSE README
jw@gallifrey:~/prince-7.1-linux$ sudo ./install.sh
Prince 7.1
Install directory
This is the directory in which Prince 7.1 will be installed.
Press Enter to accept the default directory or enter an alternative.
[/usr/local]:
Installing Prince 7.1...
Creating directories...
Installing files...
Installation complete.
Thank you for choosing Prince 7.1, we hope you find it useful.
Please visit http://www.princexml.com for updates and development news.
|
Based on the documentation
jw@gallifrey:~/prince-7.1-linux$ prince http://app.local/reports/my_report.html -o /code/client/app/public/sample.pdf
IT WORKS! but it's kinda ugly.
add pdf.css based on the boom microformat ...
add .cover-page, .chapter, .cover-notes, etc
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 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 |
@page { size: 8.5in 11in; margin: 0.75in; } p, .cover-notes { line-height: 1.7em; } .titlepage, div.chapter, div.appendix { page-break-after: always; } .titlepage { page: blank; margin: 1in 0.75in 0.75in; text-align: center; } .document-heading { font-size: 0.5in; padding: 1in 0; } .cover-notes{ font-size: 0.3in; } h1, h2, h3, h4, h5, h6 { page-break-after: avoid; } h1 { string-set: document-heading content(); } h2 { string-set: chapter-heading content(); } q::before { content: "\201C"; } q::after { content: "\201D"; } /* This can be alternated so that left and right facing pages are opposites; In my case, this isn't useful, so I merged it to one. */ @page { @top-left { content: string(document-heading, first);; } @top-right { content: string(chapter-heading, first); } @bottom { content: counter(page); } } /* don't show document title in the heading on the cover page. */ @page blank :right { @top-left { content: normal; } } |
jw@gallifrey:~/prince-7.1-linux$ prince http://app.local/reports/my_report.html -s http://app.local/stylesheets/pdf.css -o /code/client/app/public/sample.pdf
jw@gallifrey:~$
jw@gallifrey:~$ sudo gem install princely
Successfully installed princely-1.2.5
1 gem installed
---
Session Data / Cookies don't persist in IE
Rails fails with 500
I spent at least six hours isolating this issue so I thought I'd save someone else some trouble.
Say you have a site fu.com ... if you're doing any SEO work (or if you just want things to be clean) you'll 301 redirect all traffic from fu.com to www.fu.com. You can do this with Rails with a before_filter in your Rails ApplicationController.
When the user hits http://fu.com, Rails may send back a session-expiring cookie with your session id. It then redirects the user to http://www.fu.com. Rails may send back a session-expiring cookie from that domain. This confuses IE and causes it to ignore changes to the session cookie.
The trivial fix is to move the redirect upstream, in my case to Apache.
It's odd that this didn't happen in firefox or chrome, so I assume there's more to the story, but it's working now so I'm leaving it alone. :)
I spent at least six hours isolating this issue so I thought I'd save someone else some trouble.
Say you have a site fu.com ... if you're doing any SEO work (or if you just want things to be clean) you'll 301 redirect all traffic from fu.com to www.fu.com. You can do this with Rails with a before_filter in your Rails ApplicationController.
When the user hits http://fu.com, Rails may send back a session-expiring cookie with your session id. It then redirects the user to http://www.fu.com. Rails may send back a session-expiring cookie from that domain. This confuses IE and causes it to ignore changes to the session cookie.
The trivial fix is to move the redirect upstream, in my case to Apache.
It's odd that this didn't happen in firefox or chrome, so I assume there's more to the story, but it's working now so I'm leaving it alone. :)
[Valuable] parsing attributes
This post is me thinking 'out loud' about how to add custom parsing ruby gem valuable
In the past I ran into quite a few situations where I wanted to parse / process / format certain attributes as they came in. There seemed to be a lull in that so I hadn't implemented it, but now I find myself wanting it again. I'm looking at several ways to implement it and I'm not sure which one(s) are best.
Here's how you can do it now:
I like the simplicity here. No extra code is added to valuable, but it's still readable. I don't like the fact that you have to know to set it to attributes[:born_on]. That should be abstracted.
You could always call super...
option one: make no changes, call super
I initially didn't like this because I had an idea in my head of some code I wanted to add, not making changes is really growing on me. Could I just update the documentation and release a new version with 'new functionality'? :)
The code generated by valuable is absent... but looking at the generated constructor, really, we're not missing anything.
It's almost pointless to even have :klass => Time as Time.new(...) will result in 'ArgumentError: wrong number of arguments (1 for 0)', though it does provide a sort of executable comment...
option two: Indicate the method to use to parse.
I'm not fond of this. Should it be an instance or class-level method? I guess instance makes sense, but then I almost feel like it should be reading attributes instead of having a value passed in. If static, well, that makes even less sense as instance-level setters would be calling class-level parsers... enh. I guess it's not a travesty, but not my favorite.
option three: provide a proc to the has_value method
This starts to seem cluttered.
option four: separately provide parsing that would be added to the setter:
I like this alot, but it's my second-favorite to option 1, just leave it.
In the past I ran into quite a few situations where I wanted to parse / process / format certain attributes as they came in. There seemed to be a lull in that so I hadn't implemented it, but now I find myself wanting it again. I'm looking at several ways to implement it and I'm not sure which one(s) are best.
Here's how you can do it now:
1 2 3 4 5 6 7 8 |
class Beer < Valuable has_value :born_on, :klass => Time def born_on=(value) attributes[:born_on] = value.is_a?(String) ? Time.parse(value) : value end end |
I like the simplicity here. No extra code is added to valuable, but it's still readable. I don't like the fact that you have to know to set it to attributes[:born_on]. That should be abstracted.
You could always call super...
option one: make no changes, call super
1 2 3 4 5 6 7 8 |
class Beer < Valuable has_value :born_on, :klass => Time def born_on=(value) super( value.is_a?(String) ? Time.parse(value) : value ) end end |
I initially didn't like this because I had an idea in my head of some code I wanted to add, not making changes is really growing on me. Could I just update the documentation and release a new version with 'new functionality'? :)
The code generated by valuable is absent... but looking at the generated constructor, really, we're not missing anything.
It's almost pointless to even have :klass => Time as Time.new(...) will result in 'ArgumentError: wrong number of arguments (1 for 0)', though it does provide a sort of executable comment...
option two: Indicate the method to use to parse.
1 2 3 4 5 6 7 8 |
class Beer < Valuable has_value :born_on, :parse_with => :born_on_parser def born_on_parser( value ) value.is_a?(String) ? Time.parse(value) : value end end |
I'm not fond of this. Should it be an instance or class-level method? I guess instance makes sense, but then I almost feel like it should be reading attributes instead of having a value passed in. If static, well, that makes even less sense as instance-level setters would be calling class-level parsers... enh. I guess it's not a travesty, but not my favorite.
option three: provide a proc to the has_value method
1 2 3 4 5 6 |
class Beer < Valuable has_value :born_on, :parse_with => Proc.new {|value| value.is_a?(String) ? Time.parse(value) : value } end |
This starts to seem cluttered.
option four: separately provide parsing that would be added to the setter:
1 2 3 4 5 6 7 8 |
class Beer < Valuable has_value :born_on parse( :born_on ) do |value| value.is_a?(String) ? Time.parse(value) : value end end |
I like this alot, but it's my second-favorite to option 1, just leave it.