Using devise’s scoped url helpers in Cucumber; new_registration_path, new_session_path
You can use devise's scoped url helpers from cucumber, but you have to use them by their real Url Helper method names:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | module NavigationHelpers def path_to(page_name) case page_name when /the sign up page/ # dont use the helper's helper # new_registration_path(:user) # use the underlying url helper new_user_registration_path when /the sign in page/ # dont use the helper's helper # new_session_path(:user) # use the underlying url helper new_user_session_path else #...yada, yada |
cucumber.yml was found, but could not be parsed. Please refer to cucumber’s documentation on correct profile usage.
Yeah, I got that message today and wasted about 30 minutes of my life.
I hadn't changed my cuke yaml file since I started work on the app.
I tried:
* upgrading cucumber (FAIL)
* using another yaml file (FAIL)
* upgrading gherkin (FAIL)
* hard reseting the branch I was on (FAIL)
Turned out to just be a bum rerun.txt file. So I deleted it.
I need a refund on that 30 minutes.
Biting myself on the ass with Cucumber
So I spent a few hours today biting my own ass with cucumber.
If you are ever trying to "see" stuff in your page and notice that it has strangely disappeared, like oh say, your flash messages or validation errors. You may want to pay close attention if you are testing the page you are on just before hand.
I found out a sore lesson today, there is a big difference between:
1 2 | Then I am on the sign up page And I should see "Email can't be blank" |
And
1 2 | Then I should be on the sign up page And I should see "Email can't be blank" |
The difference here? "The I am on" reloads the page. I didn't know that. So I was trying to make sure I was on the right page, then checking for errors, etc. The page would reload, all my errors would be gone, and my feature was failing.
"Then I should be on" tests that the url matches the one you are on.
The more you know.
Matching Unicode characters and strings with Regexp in Ruby 1.9.2
So I've been working on a revamp of a project (still secret, ohhhh ahhh) and I needed Unicode support for multiple languages. I whipped up a pretty simple regexp and found that it didn't work for my test case.
So I've got something equivalent to this running inside some rails rspec test. And my test is failing because I'm expecting some russian words.
1 2 3 | greeting = "Добрый день." greeting.scan( /\w/u ) #=> [] |
WTF.
I double check:
1 2 3 4 5 6 7 8 | greeting = "Добрый день." pattern = /\w/u puts greeting.encoding # => UTF-8 puts pattern.encoding # => UTF-8 |
Hell, I even have "# encoding: UTF-8" at the top of the file.
Fuuuuuuuuuuuuuuuuuuuuuuu.
After some google and some irc'ing I find this answer, which solves the problem and allows for matches of unicode characters in ruby 1.9.2, but I still can't figure out what the 'p' stands for. I'm guessing "please". The problem is apparently there was an issue with \w matching unicode characters, so \w specifically only works with ASCII.
1 2 3 | greeting = "Добрый день." greeting.scan( /\p{Word}/u ) #=> ["Добрый", "день"] |
Wööt.
HamlburgerHelper sets the Table – Easily create and display standard tables in Rails
I create tables a lot in my back end for display information.
I posted a table display/create helper method on dzone that easy to use but has a ton of options.
This is the helper I currently use on my admin backend pages to create the simplest table to a pretty complex table.
Here are all of the available options and their defaults:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | :table_class => 'display_grid', # CSS class name of the table :table_id => "display_grid_#{objects.first.class.to_s.underscore.pluralize}", # CSS ID of the table :heading_class => 'display_grid_heading', # CSS class name of the first TR (one containing TH) :heading_id => "display_grid_heading_#{objects.first.class.to_s.underscore.pluralize}", # CSS ID of the first TR :th_class => 'display_grid_th', # CSS class for all TH elements :tr_class => 'display_grid_tr', # CSS class for all TR elements :td_class => 'display_grid_td', # CSS class for all TD elements :even_odd => true, # Should even/odd classes be added :format_date => nil, #nil | lambda{|datetime|} # Time formatter (receives date object, expects string) :numeric_td_class => 'numeric', # CSS class for any TDs containing a number :date_td_class => 'date', # CSS class for any TDs containing something date-like :string_td_class => 'string', # CSS class for any TDs containing a string # Any of this will create an 'Actions' heading, the lambdas receive the object, and expect a string :show_action => nil, # lambda{|object| link_to '', my_path(object)} :edit_action => nil, # lambda{|object|} :destroy_action => nil, # lambda{|object|} |
Using it is pretty easy, just drop it in your app/helpers folder and...
1 2 3 4 | display_grid(User.all, { :show_action => lambda{|user| link_to user.display_name, public_user_path(user) } :table_id => 'cool_users' }) |
Its pretty simple. It'll dump out a table, and then you can go and style it using the CSS classes/ids above.
Woot, back end DRY.
methods_like helper for finding ruby methods
Here is a little gem I have in my ~/.irbrc I use it a lot when debugging code. I tend to use call #methods a lot on objects to figure out how they quack.
Sometimes I can remember kinda what a method's name is I want to use, but doing something like the following can generate a huge amount of output especially when working with ActiveRecord
1 | my_object.methods.sort |
So I threw together this little method that adds to ruby's base Object class
1 2 3 4 5 6 7 8 | class Object def methods_like(pat) pattern = pat.is_a?(String) ? /#{pat}/ : pat self.methods.sort.select{|m| m =~ pattern } end end |
Now from IRB, Rails console, or Padrino console you can do things like:
my_collection.methods_like(/^update/) #=> [ array of method names that start with update ] user.methods_like("name") #=> [ :first_name, :last_name, :etc ] Array.new.methods_like "sort" #=> ["sort", "sort!", "sort_by"]
Its a handy little snippet when you can't remember an exact method name, and generally for me works faster than googling for it. Toss it in your ~/.irbrc and tell me what you think.
UPDATE
I added some more functionality for getting additional methods (private, protected, singleton):
class Object # pattern - string or pattern to match # access - :public, :private, :protected, :singleton, :all def methods_like(pattern, access = :public, details = false) master_method_list = case access when :public then self.methods when :private then self.private_methods when :protected then self.protected_methods when :singleton then self.singleton_methods when :all ( self.methods + self.private_methods + self.protected_methods + self.singleton_methods ).uniq end matched_method_list = master_method_list.sort.select{ |m| m =~ ( pattern.is_a?(String) ? /#{pattern}/ : pattern ) } if !details matched_method_list else details_list = {} matched_method_list.each do |current_method| details_list[current_method] = method_details(current_method) end details_list end end # Returns details about method def method_details(current_method) current_method = current_method.to_s access_level = if self.methods.include?(current_method) :public elsif self.private_methods.include?(current_method) :private elsif self.protected_methods.include?(current_method) :protected elsif self.singleton_methods.include?(current_method) :singleton end { :owner => self.method(current_method).owner, :arity => self.method(current_method).arity, :receiver => self.method(current_method).receiver, :access => access_level } end end
Now you can do:
variable.methods_like pattern, :private #=> Array of private methods with pattern variable.methods_like pattern, :all, true #=> Hash of methods with additional details
If you pass 'true' for details you will get a hash that looks like:
Array.new.methods_like "sort", :all, true #=> { "sort_by"=>{:owner=>Enumerable, :access=>:public, :receiver=>[], :arity=>0}, "sort!" =>{:owner=>Array, :access=>:public, :receiver=>[], :arity=>0}, "sort" =>{:owner=>Array, :access=>:public, :receiver=>[], :arity=>0} }
Access options available are :public, :private, :singleton, :protected, :all
Testing 404/500, Error Pages with Webrat visit method
This is a super simple snippet, and maybe there is something built into webrat, but I didn't find it. I needed to test for 404 pages in some of my tests (I was writing tests that made sure a page didnt show for disabled content). Purposely getting 404's can be annoying though since webrat opens up the 404 page in your default browser. There is a variable available in Webrat's configuration that you can use to temporarily disable this functionality. I wrapped it in the following method:
1 2 3 4 5 | def visit_but_dont_open(url) Webrat.configuration.instance_variable_set("@open_error_files", false) visit url Webrat.configuration.instance_variable_set("@open_error_files", true) end |
Throw that in your test_helper and you can start doing:
1 2 | visit_but_dont_open "Http://example.com/page/that/doesnt/exist" assert !response.ok? |
Yay, 404.
Ruby 1.9 Date#strftime adds a space on %b
So, I had a spec failing in my integration suite and I couldn't figure out what the hell it was - EVERYTHING LOOKED LEGIT. I even logged into the site, and visually verified it. Whats the dilly?
I upgraded to ruby 1.9 from ruby 1.8 and apparently, when doing strftime on date, you get a free whitespace character with "%b"
1 2 3 | # Ruby 1.8 irb(main):006:0> Date.today.strftime("%b %e, %Y") => "May 7, 2010" |
1 2 | irb(main):007:0> Date.today.strftime("%b %e, %Y") => "May 7, 2010" # TWO SPACES |
Super dumb - wasted a good 10 minutes of my day because I could see the diff between:
1 2 | "May 7, 2010" "May 7, 2010" |
In the middle of a web page full of other content.
Why the freebee space character on the %b? Dunno. I just smashed my stftime statement together and my specs are rolling.
1 | Date.today.strftime("%b%e, %Y") |
Uh, yeah - this is my bug report.
Padrino, Compass, and Sass – Working happily via Ian Serlin
My cohort, Ian Serlin, discovered this. In a project we are working on we could get Compass to play well with PadrinoRb. It seems like the #sass method doesn't care about the options being passed to it, and we kept getting stack traces rendered into our CSS files. The stack trace was ruby looking for - and failing to find compass/reset.css.
This is the code that DOESN'T work (padrino 0.9.10, compass 0.8.17, sinatra 1.0).
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 | configure do register SassInitializer #The Rack Sass reloader... Compass.configuration do |config| config.project_path = File.dirname(__FILE__) config.sass_dir = "stylesheets" config.project_type = :stand_alone config.http_path = "/" config.css_dir = "stylesheets" config.images_dir = "images" config.output_style = :compressed end end get '/stylesheets/:file.css' do content_type 'text/css', :charset => 'utf-8' # This is the doc on how to give Sass some more load paths to find the compass files. # it doesnt work :P and for that matter, neither does: # sass :file, Compass.sass_engine_options # or the set :sass, whatever_hash_here sass :file, :sass => Compass.sass_engine_options end |
Our solution was to force Sass options and Compass options to merge...
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 | configure do register SassInitializer Compass.configuration do |config| config.project_path = File.dirname(__FILE__) config.sass_dir = "stylesheets" config.project_type = :stand_alone config.http_path = "/" config.css_dir = "stylesheets" config.images_dir = "images" config.output_style = :compressed end Sass::Plugin.options.merge!(Compass.sass_engine_options) end get '/stylesheets/:file.css' do content_type 'text/css', :charset => 'utf-8' sass :file end |
Yay, magic spells - it works. You can check out more ian magic spells at ianserlin.com.
Attaching local or remote files to Paperclip and Milton Models in Rails (Mocking content_type and original_filename in a Tempfile)
I was working on a project today where I needed to import some data from MySpace accounts (yeah, MySpace), which included importing the users profile image. In the controller that did the importing I was using OpenURI to retrieve the image and then turn it into a Tempfile to be attached the the model, like so:
1 2 3 4 5 6 7 | def import #...snip tempfile = Tempfile.new( my_filename) tempfile.write open( image_url ).read @imported_user.images.create(:file => tempfile) #...snip end |
This doesn't work. It blows up missing one of two methods:
- #original_filename
- #content_type
If you inspect a normal file upload in Rails which has these methods, you'll find that is just a regular old Tempfile. But it has the methods! If you create a Tempfile manually, it won't have the methods. That's because Rails magics them on. I am not sure why they don't create a subclass like Rails::Tempfile that contains these methods and just use that. I guess its because OOP is retarded (sarcasm).
So, I wrote a little subclass that will take a file path, and quack like the magic'd rails Tempfiles you get from an upload so you can attach local files to models or even remote files.
This works pretty straightforward and I'm currently using it in production. It won't work on windows systems because the dependency on the 'file' binary. Also, some linux systems are missing this library by default, so make sure you yum|dpkg|apt|port or whatever to get it 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 25 26 27 28 29 30 31 32 | require 'open-uri' require 'digest/sha1' class RemoteFile < ::Tempfile def initialize(path, tmpdir = Dir::tmpdir) @original_filename = File.basename(path) @remote_path = path super Digest::SHA1.hexdigest(path), tmpdir fetch end def fetch string_io = OpenURI.send(:open, @remote_path) self.write string_io.read self.rewind self end def original_filename @original_filename end def content_type mime = `file --mime -br #{self.path}`.strip mime = mime.gsub(/^.*: */,"") mime = mime.gsub(/;.*$/,"") mime = mime.gsub(/,.*$/,"") mime end end |
Usage is pretty simple:
1 2 3 | remote_file = RemoteFile.new("http://www.google.com/intl/en_ALL/images/logo.gif") remote_file.original_filename #=> logo.gif remote_file.content_type #= image/gif |
Using it in your controller:
1 2 3 4 5 | def import #...snip @imported_user.images.create(:file => RemoteFile.new( url_to_image )) #...snip end |