Archive for the ‘Computers’ Category

Non-obvious “Share configuration” paths in RubyMine

No Comments »

(This was written regarding the RubyMine 4.0 EAP but it probably applies to many of the earlier versions as well.)

When you Run > Edit Configurations in RubyMine you can create a number of different configurations. One of these is a regular Ruby script which can be useful for running such tasks as guard. You select the full path to the *.rb file and then you click the Share configuration check box. You might wonder how you express those paths as relative to the project path; after all you want to share the configuration with your teammates and their paths won't likely match your own.

Well it turns out there's no secret sauce to make this work; RubyMine will substitute the macro value $PROJECT_DIR$ if the script's path is relative to the project you currently have open. In the UI you'll see the fully expanded path, but when you commit your shared project settings the macro value is what is actually recorded in the *.xml file. When your teammates pull down your shared configurations it will be relative to their project's path.

So to get Guard (with Spork) running in RubyMine I did the following:

  1. Created a run_guard.rb file in my project's root
  2. #./run_guard.rb
    exec 'guard'
  3. RubyMine: Run > Edit Configurations
  4. Hit the + and add a new Ruby script
  5. Name it Guard, select the full path to the run_guard.rb, select the Bundler tab, check run in the context of Bundler (for good measure)
  6. .idea is correctly in my .gitignore file... but the shared configs live under .idea/sharedConfigurations/
  7. git add -f .idea/sharedConfigurations/Guard.xml and commit, push

Run the new Guard configuration and you'll see it display in one of the output panes at the bottom of the screen by default. When you save your specs it will automatically run as normal (but beware that ⌘S saves all files).

We also found out that pry statements in your RubyMine hosted Guard process won't allow you to interact with the running test session; instead the process will just hang.

Update: some more useful RSpec information with RubyMine:

Built in spec task: If your spec task is dying because you've configured a DRb server via Guard (using Spork) and you don't plan on running the built-in Spork task within RubyMine you'll need to make some changes to your Spork.prefork block and add an environment variable for the Guard script itself (Run > Edit Configurations) named "RUBYMINE_HOME" and point it to your RubyMine's application path (i.e. for me its /Applications/RubyMine EAP.app/). Now when Guard is running your built-in rspec task can execute without dying.

growlnotify: if you still want Growl notifications for your RubyMine hosted Guard you may need to sudo ln -s /usr/local/bin/growlnotify /usr/bin/growlnotify.


RSpeccing POST and raw data (using RAW_POST_DATA)

No Comments »

I got a request over the weekend to support a client library on the Android platform that cannot submit multipart form data easily. The request was to allow the client to send the raw bytes as the HTTP request body. In order to implement this functionality I of course wanted to spec it out first to make sure I was writing this correctly - it isn't every day that I deal with the raw request body after all.

My spec ended up looking like this...

#./spec/controllers/file_test_api_controller_spec.rb
⋮
  describe "#raw_upload" do
    before do
      # file_path points to a file I used dd to generate that is 11,776 bytes
      bytes = File.open(file_path, 'rb').read
      @request.env['RAW_POST_DATA'] = bytes
      post :raw_upload, { }, 'CONTENT_TYPE' => 'application/octet-stream'
      @request.env.delete('RAW_POST_DATA')
    end
    subject { response }
    its "status" do
      should == 200
    end
    its "body" do
      should =~ /size.*11776/m
    end
  end
⋮

To access this data directly in your controller, you just use request.raw_post.

Its worth noting that my controller replies with a receipt in JSON that includes the size of the received data which is why the spec regexes the body for it - there's no automagic occurring with my controller's response.

This approach does not work with HTTP PUT as the RAW_POST_DATA request environment variable is cleared when a PUT is performed.

Reference: How to send raw post data in a Rails functional test?


button_to UrlHelpers all in a row

No Comments »

If you are using a series of button_to UrlHelpers in Rails and want the buttons to line up horizontally on a row you can use this CSS to accomplish it:

/* ./app/assets/stylesheets/button_to.css.scss */
form.button_to {
	margin:0;
	padding:0;
	display:inline;
}

form.button_to div, form.button_to div input {
	display:inline;
}

If you are using Rails 3.x's asset pipeline, remember to add a line to your application.css to include the button_to asset - assuming you're breaking out your styles into separate files.


RSpec/unit testing permanent signed cookies

No Comments »

Ran into a simple problem today while I was speccing a new controller in our project. We generate some signed cookies for devices which check into our system and then we use those cookies to identify these devices when they return. Unfortunately the ActionController.TestRequest @request instance variable you get when using rspec-rails has the cookies collection as a basic hash and no cookies= method defined. This means that attempting to invoke permanent or signed on a hash results in a runtime error and you can't just assign the cookies collection to a valid ActionDispatch::Cookies::CookieJar instance.

You can get around this by going around the missing attribute setter and changing the instance variable directly.

#./specs/controllers/some_controller_spec.rb
   # a new device is created here...
   ⋮
   @request.instance_variable_set(:@cookies, ActionDispatch::Cookies::CookieJar.build(@request))
   # the token is what we use to identify the device on subsequent requests
   # so our specs need to be able to create it when necessary
   @request.cookies.permanent.signed[:token] = [device.device_id, device.secret]
   ⋮
   # remainder of spec omitted

If you're doing stuff with the regular cookies hash you will need to merge! your cookies hash with the @request.cookies hash before building and assigning the full blown ActionDispatch::Cookies::CookieJar instance.

Reference: How to test cookies.permanent.signed in Rails 3


BootstrapFormBuilder, or how ActionView::Helpers::FormBuilder ruined my day

No Comments »

There is surprisingly little up to date information about ActionView::Helpers::FormBuilder. That's because mostly it hasn't changed. I'm always afraid of documentation going back to 2008 when we're talking about Rails because 99% of the time its just not quite going to work.

A little bit of background: we're using Twitter's Bootstrap in our project. There's a bit of ceremony around each field such that you need to do a .clearfix div, then a label, then a .input div and finally the input. I want to eliminate all those keystrokes so I can just do:

#./app/views/c2dm/new.html.haml
form_for @message, :url => {:action => 'create'} do |f|
  %fieldset
    = f.text_field :registration_id
    = f.text_field :collapse_key
    = f.text_area :message
    .actions
      %input.btn.primary{:type=>"submit"}

Here's the no-nonsense way of achieving this by adding a new class to your app/helpers/application_helper.rb (don't forget to restart your Rails server when you do this):

#./app/helpers/application_helper
⋮
# add these lines after the ApplicationHelper module
class BootstrapFormBuilder < ActionView::Helpers::FormBuilder
  helpers = field_helpers +
              %w{date_select datetime_select time_select} +
              %w{collection_select select country_select time_zone_select} -
              %w{hidden_field label fields_for} # Don't decorate these
  helpers.each do |name|
    define_method(name) do |field, *args|
      options_index = ActionView::Helpers::FormBuilder.instance_method(name.to_sym).parameters.index([:opt,:options])
      if options_index.nil?
        options = args.last.is_a?(Hash) ? args.pop : {} # pretty sure this shouldn't happen
      else
        options = args[options_index - 1] # -1 to account for the method name argument
      end
      label = label(field, options[:label], :class => options[:label_class])
      @template.content_tag(:div, :class => 'clearfix') do
        @template.concat(label)
        @template.concat(@template.content_tag(:div, :class => 'input') { @template.concat(super(field, *args)) })
      end
    end
  end
end

ActionView::Base.default_form_builder = BootstrapFormBuilder
# you can also register this in ./config/application in the config block
# but I was not having a lot of success going that way
# which is why I moved it to the ./app/helpers/application_helper.rb file

Ideally you'd add this somewhere outside of application_helper.rb and load it properly.

What I referenced:

advanced rails studio: custom form builder
Form Builders in Rails
Working With and Around FormBuilder

Updated: 12/21/2011 for handling methods where options isn't the last param.