Posted by admin on Oct 14, 2010 in
general computing,
ruby
Yesterday, one of my inter-web buddies IM’d me and asked if I had used Typhoeus before. I said yes, so he asked me if it was possible to follow redirects using it. He said he google’d it and nothing turned up.
I sharply responded, “LOOK AT THE CODE!”. We had some banter back and forth and a few minutes later he was automatically following redirects. It seems these days that developers often think if something does not turn up in a google search, it does not exist.
via Stop Googling // RailsTips by John Nunemaker.
Posted by admin on Mar 3, 2010 in
rails,
ruby,
tdd
I’ve long put off testing my controllers because of user authentication and nested controllers, dealing with stubs, etc.
But today, a fully working test!
As background, Advertisers have many trackers and the routes look like this:
1 2 3 4 5 6
| # config/routes.rb
ActionController::Routing::Routes.draw do |map|
map.resources :advertisers do |advertisers|
advertisers.resources :trackers
end
end |
To set everything up in the specs, I included all the files in the spec/support directory and used Mocha as my mock framework
1 2 3 4 5 6
| # spec/spec_helper.rb
Dir[File.expand_path(File.join(File.dirname(__FILE__),'support','**','*.rb'))].each {|f| require f}
Spec::Runner.configure do |config|
config.mock_with :mocha
end |
Then I set up my factories (rather than fixtures) using Factory Girl
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| # spec/factories.rb
Factory.define :user do |user|
user.sequence(:login) { |n| "username#{n}" }
user.password 'password'
user.password_confirmation { |u| u.password }
user.sequence(:email) { |n| "email#{n}@example.com" }
user.first_name "Mama"
user.last_name "Foo"
end
Factory.define :advertiser do |advertiser|
advertiser.name 'Advertiser 1'
end
Factory.define :tracker do |tracker|
tracker.name 'Tracker 1'
end |
Now we get down to brass tacks. In order to make my tests DRY (appropriately) and allow for all my controllers to test if someone is logged in and has access, I set up this shared context
1 2 3 4 5 6 7
| # spec/support/user_authentication.rb
describe "an admin is logged in", :shared => true do
before(:each) do
controller.stubs( :login_required => true)
controller.stubs( :current_user => Factory.build(:user, :login => 'admin', :roles_list => ["super"]))
end
end |
From there, all we need to do is put it all together, setting up trackers parent @advertiser and the @tracker we’ll be using and stubbing the ActiveRecord find so that it always returns @advertiser
1 2 3 4 5 6 7 8 9 10
| # spec/controllers/trackers_controller.rb
describe TrackersController do
it_should_behave_like "an admin is logged in"
integrate_views
before(:each) do
@advertiser = Factory.create(:advertiser)
@tracker = @advertiser.trackers.create(Factory.attributes_for(:tracker))
Advertiser.stubs(:find => @advertiser)
end |
Now we simply specify the part of the path that is needed to find the nested route by using :advertiser_id => @advertiser
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
| # spec/controllers/trackers_controller.rb
it "index action should render index template" do
get :index, :advertiser_id => @advertiser
response.should render_template(:index)
end
it "show action should render show template" do
get :show, :advertiser_id => @advertiser, :id => @tracker
response.should render_template(:show)
end
it "new action should render new template" do
get :new, :advertiser_id => @advertiser
response.should render_template(:new)
end
it "create action should render new template when model is invalid" do
Tracker.any_instance.stubs(:valid?).returns(false)
post :create, :advertiser_id => @advertiser
response.should render_template(:new)
end
it "create action should redirect when model is valid" do
Tracker.any_instance.stubs(:valid?).returns(true)
post :create, :advertiser_id => @advertiser
response.should redirect_to(advertiser_tracker_url(@advertiser, assigns[:tracker]))
end
it "edit action should render edit template" do
get :edit, :advertiser_id => @advertiser, :id => @tracker
response.should render_template(:edit)
end
it "update action should render edit template when model is invalid" do
Tracker.any_instance.stubs(:valid?).returns(false)
put :update, :advertiser_id => @advertiser, :id => @tracker
response.should render_template(:edit)
end
it "update action should redirect when model is valid" do
Tracker.any_instance.stubs(:valid?).returns(true)
put :update, :advertiser_id => @advertiser, :id => @tracker
response.should redirect_to(advertiser_tracker_url(@advertiser, assigns[:tracker]))
end
it "destroy action should destroy model and redirect to index action" do
delete :destroy, :advertiser_id => @advertiser, :id => @tracker
response.should redirect_to(advertiser_trackers_url(@advertiser))
Tracker.exists?(@tracker.id).should be_false
end
end |
Works! And works great! A minimal and excellent way to test your controllers, especially for access. You can easily create additional shared contexts with different user permissions and extend out the tests to make sure users that don’t have access can properly access them.
Posted by admin on Feb 27, 2010 in
ruby
Peepcode has a blog and it is managed in a very efficient and unique way. Everything is checked into git and pushed, no database involved–it’s kindof incredible. Check out the stack here:
About this Blog | Free PeepCode Blog.
Posted by admin on Feb 21, 2010 in
python,
ruby
When you’re discussing efficiency, a lot of what comes up is the details. There is something to be said for the “beauty” of limitation and the “efficiency” of beautiful things–especially the efficiency of our brains processing it.
A talk about the Zen of Python, monkey patching (several times), the Ruby community's reckless hastiness, the syntax of RSpec and cucumber, beauty and ugliness in languages and testing tools, the complexity of the languages' grammars, syntactic vs. semantic complexity, the relative taste of grasshoppers and tree bark, etc., etc.
<object width=”400″ height=”225″><param name=”allowfullscreen” value=”true” /><param name=”allowscriptaccess” value=”always” /><param name=”movie” value=”http://vimeo.com/moogaloop.swf?clip_id=9471538&server=vimeo.com&show_title=1&show_byline=1&show_portrait=0&color=&fullscreen=1″ /><embed src=”http://vimeo.com/moogaloop.swf?clip_id=9471538&server=vimeo.com&show_title=1&show_byline=1&show_portrait=0&color=&fullscreen=1″ type=”application/x-shockwave-flash” allowfullscreen=”true” allowscriptaccess=”always” width=”400″ height=”225″></embed></object><p><a href=”http://vimeo.com/9471538″>Python vs. Ruby: A Battle to The Death</a> from <a href=”http://vimeo.com/user1043515″>Gary Bernhardt</a> on <a href=”http://vimeo.com”>Vimeo</a>.</p>
via Extra Cheese.
Posted by admin on Feb 12, 2010 in
rails,
ruby
As long as we’re talking about efficiency here, one of the ways to be more efficient is to use the right tool for the job. I’ve done PDF generation on 3 different projects but the PDF generation I did yesterday was by far the easiest. What I thought would take me 2 days ended up taking about 3 hours (with research, etc).
If you’re not using Ruby to automate some part of your job or life, I feel sad for you (at least a little). The next time you need to generate PDFs, why not try out the excellent Prawn library? Not familiar, you say? Well, let’s dive right in, shall we?
For those of you that used Prawn in an earlier 0.3 form, it’s recently been drastically improved and released as 0.7 in a push towards 1.0. The APIs are very full featured (if sometimes a wee bit clunky–but PDF generation is a messy business) and simple to use. All of this is even better when integrating Prawn into Rails as a template builder using prawnto:
1
| ./script/plugin install git://github.com/huerlisi/prawnto.git |
Even though thorny-sun originally wrote prawnto, their branch is no longer maintained, it appears. Thank goodness for github since huerlisi seems to have picked up right where they left off.
Once we’ve got prawnto installed, there isn’t actually anything else we need to do to be ready to generate PDFs in our views. Let’s start of with something useful. A table in show.pdf.prawn:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
| pdf.font 'Courier' do
pdf.table object.line_items.collect {|li|
[
li.description,
(li.quantity.nil? ? "" : "#{li.quantity}"),
(li.rate.to_f == 0 ? "" : number_to_currency(li.rate)),
(li.amount.to_f == 0 ? "" : number_to_currency(li.amount))
]
},
:font_size => 8,
:vertical_padding => 2,
:headers => ["Description", "Quantity", "Rate", "Amount"],
:header_color => "888888",
:header_text_color => "FFFFFF",
:border_width => 1,
:width => pdf.bounds.width,
:column_widths => {0 => pdf.bounds.width-180},
:align => {2 => :right, 3 => :right}
end |
Tell me that isn’t readable? 30 seconds and you can tell exactly what that’s doing.
And we can even extract it to a partial! The only thing you have to do to make it a partial is rename the pdf object to something else, conventionally “parent_pdf”
1 2 3 4 5 6 7
| parent_pdf.font 'Courier' do
parent_pdf.table object.line_items.collect {|li|
[
li.description,
(li.quantity.nil? ? "" : "#{li.quantity}"),
...
# etc... |
And then call the partial from show.pdf.prawn
1
| render :partial => 'object', :locals => {:object => @object, :parent_pdf => pdf} |
and index.pdf.prawn
1 2 3 4 5 6
| first = true
@objects.each do |object|
pdf.start_new_page unless first
render :partial => 'object', :locals => {:object => object, :parent_pdf => pdf}
first = false
end |
And make sure our controller actions can respond to the ‘.pdf’ format.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
| def show
@object = Object.find(params[:id])
respond_to do |format|
format.pdf do
send_data(render(:template => 'objects/show.pdf.prawn', :layout => false),
:filename => "#{object.name}.pdf",
:type => 'application/pdf',
:disposition => 'attachment')
end
end
end
def index
@objects = Object.all
respond_to do |format|
format.pdf do
send_data(render(:template => 'objects/index.pdf.prawn', :layout => false),
:filename => "objects.pdf",
:type => 'application/pdf',
:disposition => 'attachment')
end
end
end |
Everything is separated where it needs to be. All the view logic is in the views, model logic is in the models, and controller logic isn’t duplicated elsewhere.
Make sure and check out the various Prawn examples and do your next PDF generation right.
Posted by admin on Feb 9, 2010 in
rails,
ruby
Upgrading applications is good sport and all, but everyone knows that greenfielding is where the real fun is. At least, I love greenfielding stuff a lot more than dealing with old ghetto cruft that has 1,900 test failures and 300 errors, 20,000 line controllers, and code that I’m pretty sure is actually a demon-brand of PHP.
Building a totally new app in Rails 3 is relatively simple especially if you’ve done it in previous Rails versions, but there a few changes that can trip you up. In the interest of not missing a step someone may need, this post is a simple walkthrough of building a new app with Rails 3.
via omgbloglol – The Path to Rails 3: Greenfielding new apps with the Rails 3 beta.
Posted by admin on Feb 8, 2010 in
ruby
While the Python version may not be quite as pretty, nothing about them screams “Ruby has much stronger capabilities here”. Instead, by using examples like Sinatra, Rubyists trade in an argument about great semantic power for one about superficial beauty.
Rubyists, Pythonistas and others working on web development share a common language in JavaScript. When describing blocks to “outsiders” who share a common knowledge of JavaScript, we tend to point at JavaScript functions as a close analogue. Unfortunately, this only furthers the confusion.
On the Ruby side, when PHP or Java announces that they’re “adding closures”, many of us don’t stop to ask “what kind of closures?”
Let’s cut to the chase and use a better example of the utility of Ruby blocks.
via The Building Blocks of Ruby « Katz Got Your Tongue?.