agaskar.com

Aug 05 2010

The nokogiri install locally magic.

If you’re building your own libxslt and libxml2 because you’re on shared hosting, the *right* gem install magic is :

gem install nokogiri — —with-xml2-lib=<YOUR_INSTALL_DIR>/lib —with-xml2-include=<YOUR_INSTALL_DIR>/include/libxml2 —with-xslt-lib=<YOUR_INSTALL_DIR>/lib —with-xslt-include=<YOUR_INSTALL_DIR>/include/

You should be ./configure —prefix=<YOUR_INSTALL_DIR> when you compile libxml2 and libxslt.

The docs recommend

gem install nokogiri — —with-xml2-lib=/home/joe/builds/lib \
—with-xml2-include=/home/joe/builds/include/libxml2 \
—with-xslt-lib=/home/joe/builds/lib \
—with-xslt-include=/home/joe/builds/include/libxslt

This is close, but not close enough if you’re not used to compiling your own libraries. Taking a peek at mkmf.log is pretty helpful here too. Good luck!!!!

Comments (View)
Apr 22 2010
Commands to take advantage of bash’s Emacs Mode:
ctrl-a Move cursor to beginning of line
ctrl-e Move cursor to end of line
meta-b Move cursor back one word
meta-f Move cursor forward one word
ctrl-w Cut the last word
ctrl-u Cut everything before the cursor
ctrl-k Cut everything after the cursor
ctrl-y Paste the last thing to be cut
ctrl-_ Undo
Comments (View)
Mar 26 2010

Removing a file from git …. FOREVER

Successfully used a combination of this Stack Overflow question (Git: Remove file accidentally added to the repository.) and this Github Guide (Guides: Completely remove a file from all revisions) to kill some files from my repo for good. For those of you wondering why you’d ever want to do this: git sends all deltas when you checkout, meaning every file ever committed gets sent down the wire, even if you `git rm` it later. Kinda sucks if you accidentally check in a 15, 20M file that you have to download only to delete immediately. In my case the file was only 500k, but I wanted to kill it before I made too many more commits. Here’s the exact command sequence I ran:

  1. First, make a backup of your local repo, and make sure there’s no local commits. No need to have things get confusing.
  2. git filter-branch --index-filter 'git rm --cached --ignore-unmatch all_the_files.you want_to_remove.here' <OLDEST COMMIT SHA WITH THE FILES YOU WANT TO REMOVE>..HEAD
    Make sure you get all the files you want to kill in one swoop — git throws an error if you try to re-run this command without pushing/refreshing
  3. git push --force
    Github recommends
    git push --force --verbose --dry-run
    and I’m assuming this’ll throw an error if something terrible is about to happen, but it printed nothing in my case, so I just moved on. It couldn’t hurt to try.

I’m not sure I’d use this on a repo where I was working with more than a few other people; I imagine everyone would have to re-checkout the repo from master, so it could be pretty disruptive. Another good reason to look at the changesets before you push.

If you haven’t actually pushed yet, but the file you want to remove isn’t in your last commit, you can `git reset SHA`, which will jump you to that commit and move already committed files to your staging where you can then modify your commit. If you just want to remove a file in your last commit (and you haven’t actually pushed yet), git rm that file and use `git commit —amend`

Comments (View)
Feb 27 2010

authlogic doesn’t seem to like html multipart in tests

      xhr :post, :create, { :item_id => @item.id.to_param, :Filedata => fixture_file_upload('images/sample1.jpg', 'image/jpeg') }, :html => { :multipart => true }
fails
      xhr :post, :create, { :item_id => @item.id.to_param, :Filedata => fixture_file_upload('images/sample1.jpg', 'image/jpeg') }
succeeds.

not going to track this one down, because my test was green without it. Maybe this is blowing away some important headers? …

Comments (View)
+

Rails Routing Namespaces with Nested Routes can cause Model failures.

Working on my side project, I refactored some controllers into an admin namespace, resulting in a directory tree that looked something like this:
-controllers/
  -admin/
    -item/
      -photo_controller.rb
    -item_controller.rb
All the tests passed, yet whenever I hit my (previously working) admin/items controller, I got:
NoMethodError (undefined method `find' for Admin::Item:Module):
  app/controllers/admin/items_controller.rb:7:in `index'

It looked like the route was somehow forcing the namespacing of the model. I went nuts googling for it and found zero explanations. Finally, on a hunch, I renamed the item directory to items and the photo_controller to Admin::Items::PhotoController instead of Admin::Item::PhotoController and everything worked.

Another option is to use ::Item in your controller instead of Item. I think I might go with this one — would rather be more specific than resort to naming tricks.

I’m still bewildered as to how or why this is happening — I can’t quite see how having an Admin::Item:: namespace means that all of the sudden, Item will now refer to Admin::Item, although I do have a pet theory. Perhaps when Item is not found in the current namespace, it goes UP a namespace and eventually hits the model. Since I now have an Admin::Item, it doesn’t bother looking in the main namespace.

I can’t believe this was so tough to google for. I imagine this would nail anyone who has a nested route in a namespace. I’m a bit surprised it’s not a more common error.

I’m assuming tests didn’t fail because the Admin::Item::PhotosController was not loaded during the Admin::ItemsController test.

Comments (View)
Feb 20 2010

Active Record DB Types: A Reference

Native types:

add_column :native_type, :name, :options
:primary_key 
:string 
:text
:integer 
:float
:decimal
:datetime
:timestamp 
:time 
:date 
:binary 
:boolean

Native Type Options:

:limit - Requests a maximum column length. This is number of characters for :string and :text columns and number of bytes for :binary and :integer columns.
:default - The columnā€˜s default value. Use nil for NULL.
:null - Allows or disallows NULL values in the column. This option could have been named :null_allowed.
:precision - Specifies the precision for a :decimal column.
:scale - Specifies the scale for a :decimal column.

Table definitions:

  create_table :products do |t|
    t.integer :shop_id, :creator_id
    t.string  :name, :value, :default =%gt; "Untitled"
    t.timestamps
  end
You can use any native type, or the following helpers.

timestamps

adds created_at and updated_at timestamp columns to your table.
...
t.timestamps
...

references

Adds the integer field “#{name}_id”. Also adds the string field “#{name}_type” if polymorphic is true. You can pass a hash to polymorphic and specify a default if desired.
create_table :taggings do |t|
    t.references :tag
    t.references :tagger, :polymorphic => true
    t.references :taggable, :polymorphic => { :default => 'Photo' }
  end

Auto-generate an add_column migration

There is a special syntactic shortcut to generate migrations that add fields to a table.
 script/generate migration add_fieldname_to_tablename fieldname:string

Comments (View)
Feb 17 2010

has_many :through, accepts_nested_attributes_for, and validations

I had a need to write some code that would permit the following:

it "accepts attributes for item_photos" do
    photo = Factory(:photo)
    item = Item.create!(Factory.attributes_for(:item, :item_photos_attributes => [{:photo_id => photo.id}]))
    item.item_photos.should have(1).item_photo
    item.photos.first.should == photo
end
Basically, you can use nested attributes to when creating items to create lookup records for existing photos. Of course, the create kept failing due to the item_photo in question missing an item (well, actually … I started with a create, which of course happily continued on its way until I tried to look at item photos and it was blank. The lesson is that you should ALWAYS test that your create or saves have occured, either with a should be_true or a bang method so they explode). This blew my mind — how does accept_nested_attributes_for even work if you need to have an id before saving child associations? Well, it was my fault, of course. My item_photos model looked like this:
class ItemPhoto < ActiveRecord::Base
  belongs_to :item
  belongs_to :photo

  validates_presence_of :item
  validates_presence_of :photo
end
I added the validations because I believed it would be silly to have an item_photo without an associated item or photo. What would you do with such a thing? Of course, my overzealous validating meant my accept_nested_attributes could never hope to succeed. Removing these validations made the test pass happily. Basically, this seems to indicate that Rails can’t yet handle validations on parent belongs_to associations in children yet, so you’re probably going to have to skip them. It sounds like this is possibly going to make it into a future version of rails, but if not, there you have it: a simple solution for a foolish problem that is *really* hard to google for.

Comments (View)
Jan 26 2010

Fun (and evil) tricks with rspec

      original_glob = Dir.method(:glob)
      Dir.stub!(:glob).and_return do |glob_string|
        if glob_string =~ /public/
          glob_string
        else
          original_glob.call(glob_string)
        end
      end
Of course, you shouldn’t do this because return blocks on stubs (calculated return blocks) are evil. Still fun, though.

Comments (View)
Jan 23 2010

JSON.stringify bug with Native FF Implementation

Firefox past 3.5.4 natively implements JSON.stringify with replacers, similarly to the way JSON2 works. However, it’s doing something wrong (optimization related?). Supposedly, you can pass stringify a replacer function as a second argument and it will use whatever is returned from that argument as the value in the serialized copy. HOWEVER, if you pass a value back that contains the same values (but is not === to) the original value, the JSON.stringify uses the original value instead. This sucks for me, because I want to pass back an array with the toJSON method wiped, without destroying the (incorrectly implemented by Prototype) toJSON method on the original. Here’s a jasmine spec:

function json2PrototypeFix(key, value) {
  if (typeof this[key] == 'object' && Object.prototype.toString.apply(this[key]) === '[object Array]') {
    var copy = this[key].slice(0);
    this[key] = [1];
     return copy;
  } else {
    return value
  }

}
describe('JSON with protoype', function () {

 it('should properly stringify an object with child arrays', function() {
    var array = [1,2];
    var obj = {"foo": array};
    var result = JSON.stringify(obj, json2PrototypeFix);
    expect(result).toEqual("{\"foo\":[1,2]}");
  });
});
The failure I get here is
Expected '{"foo":"[1]"}' to equal '{"foo":[1,2]}'.
which implies I’m using the original value, even though I passed back the copy I made of it. If I allow Crockford’s original JSON2 to overwrite the stringify function, then everything works as expected. This is super frustrating — both Prototype AND Firefox are broken in this case, so I can’t reliably fix the parts of Jasmine that need JSON.stringify to work correctly when Prototype is present. I think I’m just going to check for the presence of prototype and then just use their toJSON, instead of fixing the issue using JSON2’s replacer support (which isn’t going to be present everywhere anyways — sounds like it’ll break in browsers that implement JSON.stringify without the replacer arg; ie FF

Comments (View)
Dec 30 2009

Tracking a remote fork locally with Git

git add remote SomeRemote git://github.com/SomeRemote/some-project.git
git fetch SomeRemote
git branch --track SomeRemote SomeRemote/master
git checkout SomeRemote
Now you’ve got a local branch (named after the user who created it) that is tracking changes to that repo. Meaning if you
git pull
in there, you’ll get their latest changes. If you’ve got someone you frequently collaborate with who makes changes to their own fork, this is super handy.

Comments (View)
Page 1 of 8