Seq vs Seek

In Clojure, something that is “seq”-able can be turned into an object (a seq) that implements an interface that can provide the first item of an ordered list, aka the head, and the rest of the items, aka the tail. As usual in Clojure, seqs and their methods provide various guarantees such as immutability.

The unfortunate part about the situation is that “seq” is pronounced “seek”. “Seq-able” sounds like “seekable”. Seekability, however, implies a completely different set of properties than a seq. Something that is seekable typically allows random access (access any member of the collection at a cost of O(1)) for example via multiplication of an index by an object size. The seq interface, meanwhile, is O(n) for random access even if the underlying data structure could support random access.

Thus, if you’re listening to a Clojurian speak, keep in mind that when they say “seek”, they’re really saying “seq”.

Storing compressed blobs in Sqlite3 with Datamapper for Ruby

If you’re trying to store a blob (in my case, compressed text) into a Sqlite3 database with Datamapper and you’re running into this error:

Zlib::BufError: buffer error

Try base 64 encoding it, as hinted by this file: https://gist.github.com/721922

require 'zlib'
require 'base64'

class Foo
  include DataMapper::Resource

  property :compressed_file_content, Binary, accessor: :private

  def file_content=(str)
    @inflated_file_content = str
    deflator = Zlib::Deflate.new()
    self.compressed_file_content = Base64::encode64(deflator.deflate(@inflated_file_content, Zlib::FINISH))
    deflator.close
  end

  def file_content
    if @inflated_file_content
      @inflated_file_content
    else
      inflator = Zlib::Inflate.new
      @inflated_file_content = inflator.inflate(Base64::decode64(compressed_file_content))
      inflator.finish
      inflator.close

      @inflated_file_content
    end
  end
end

It’s as simple as that. No need to use SQLite3::Blob, for example.

Interpreting content outside ERB tags as unsafe

I drafted this back in 2012… publishing it now in 2016 because I’m tired of all these drafts laying around.

ERB interprets all content outside of ERB tags as safe. That is, ERB does not escape anything outside of ERB tags. Therefore, if you want to put some content into an HTML attribute, you’re forced into putting that content into a string. I find it inconvenient sometimes that I have to put everything into a String. It might end up looking very messy. So, I tried to find a way to simply use the standard ERB approach of putting the content outside of ERB tags.

My first instinct was to use ActionView::Helpers::CaptureHelper.capture to turn the content into a string, which I could then escape. Unfortunately, capture() also interprets the content as safe, and marks the string as such. Using h() has no effect.

After looking at the source of capture() and seeing that it uses a buffer to accumulate the String, I came up with a solution: provide my own buffer which is marked unsafe:

class UnsafeBuffer < ActiveSupport::SafeBuffer
  def html_safe?
   false
  end
end

To use it, pass it to with_output_buffer along with a block that returns a string. Even if the string is safe, the buffer is marked unsafe so the string will end up being escaped. In the example below, I am using capture() to produce a safe string from content outside the ERB tags.

<div data-stuff="
  <%= with_output_buffer(UnsafeBuffer.new) {
    capture do %>
      My <span class="awesome">unsafe content</span>
  <% end } %>
">

Rant about Rspec-Rails

It’s stuff like this that makes Rails and its accompanying toolset a pain in the ass.

If you want a spec to check that your controller rendered a specific thing, you can’t just mock the “controller.render” method. Why? In Rails-land, apparently controller.render is so magical that your mock expectation will receive no arguments, even if your controller passed arguments to the render method. It’ll say, “got: (no args)”

Instead, you have to use the RenderTemplateMatcher with have_rendered or rendered_template (they’re the same).

That, in turn, means you have to actually let the render call complete normally, which may violate the isolation of your controller spec.

Or, if you’re like me, it gives you “ActionView::MissingTemplate: Missing template” even though the template path is accurate. This has something to do with the EmptyTemplatePathSetDecorator mentioned in the error.

At this point, you search the internet until you discover that “By default, controller specs do not render views.” However, strangely, at the same time, “NOTE: unlike rspec-rails-1.x, the template must exist.” Still no good explanation why your completely valid template isn’t being found.

So then you try adding “render_views” to your test, but find that it’s configured to only accept production templates, not template files that you have in your spec directory. So now you have to provide mocks or stubs for all the data that your chosen production template needs. So obviously that’s not a good way to go.

So then you back out the “render_views” statement, and suddenly everything’s working. What?!

Turns out that by default Rspec-Rails doesn’t actually render any templates, but it does look for the template file in the standard file paths (app/views). So don’t try to outsmart Rspec by providing your own view specifically for your spec: it won’t be able to find it.

What a waste of time.

PS: Due to limitations of ActionController::TemplateAssertions$assert_template, which RenderTemplateMatcher delegates to, you can’t check both the template and the layout at the same time. You have to use two separate statements:
response.should have_rendered template
response.should have_rendered layout: layout

Fog::Storage::AWS::Files#length vs. #all.length

Beware thee calling the #length method on a Fog::Storage::AWS::Files object! It seems to include recently destroyed files!

Instead, you should use #all.length

# Includes destroyed files!!
Fog::Storage.new(my_connection).directories.get(my_directory).files.length

# Better!
Fog::Storage.new(my_connection).directories.get(my_directory).files.all.length

Rspec-rails’s rake tasks not loaded in Rails engine

Having trouble getting the Rspec rake tasks to appear when you run “rake -T” in your Rails engine? The dummy app (which you should have if you specified –full) is not pulling in the Bundler dependencies, and as a result the rspec-rails Railtie subclass is not being created.

The fix, for me at least, is changing spec/dummy/config/application.rb line 11 or so to:

Bundler.require(*Rails.groups)

You should now have tasks such as “rake app:spec” available.

You may also need to update your root Rakefile to run the specs by default, by adding “task :default => ‘app:spec'”

Also see my issue on the railties Github

This was with Rails 3.2.8.

Mongoid: NoMethodError: undefined method `sub’ for :section:Symbol

If you recently added a Mongoid relationship that defines a specific “class_name” so that you can have a custom relationship name, and you’re getting an error like

“NoMethodError: undefined method `sub’ for :yourclassname:Symbol”

it might be coming from Mongoid::Relations::Metadata.class_name, which assumes that class_name is a string, not a symbol. Change the class_name on your relationship definition to a string, and it should be fixed.

ActiveModel JSON serialization

If you have code:

<%= JSON.pretty_generate(JSON.parse(@myobject.as_json)) %>

that results in "can't convert Hash into String"
Or

<%= JSON.pretty_generate(@myobject.as_json) %>

That results in: "undefined method `key?' for #"

Try:

<%= JSON.pretty_generate(JSON.parse(@page.to_json)) %>

And if as_json or to_json is not obeying your “only:”, “include:”, or “except:” directives, make sure you include ActiveModel’s JSON if your object is not an ActiveRecord object (or other object that inherits it already).

Along with that, you’ll need to implement an attributes method. As mentioned in ActiveModel::Serialization, “You need to declare some sort of attributes hash which contains the attributes you want to serialize and their current value.” The weird thing is that it doesn’t matter what the values returned in the hash are. It only obeys the keys, calling .send(key) on your object to get the value for each key.

class MyThing
  include ActiveModel::Serializers::JSON
  ...
  # Needed for ActiveModel::Serialization and things that use it (such as JSON)
  def attributes
    {
        'myattr' => nil,
        'anotherattr' => nil
    }
  end
end

HTTP Status 418: I’m a Teapot

After seeing this in Rack::Utils (my IDE even highlighted it because it’s the only one in double quotes):

HTTP_STATUS_CODES = {
      100  => 'Continue',
      101  => 'Switching Protocols',
...
      418  => "I'm a Teapot",
...
}

I had to look it up: http://tools.ietf.org/html/rfc2324

Thanks to laserlemon I can finally implement my fully web-controlled coffee pot with Sinatra on Rack!

Origin 1.0.5 yanked

If you’re using Mongoid::Paranoia, and you’re running into a problem that looks like this:


/Users/you/.rvm/gems/ruby-1.9.3-p194/gems/origin-1.0.5/lib/origin/extensions/nil_class.rb:30:in `__expanded__': wrong number of arguments (0 for 1) (ArgumentError)
	from /Users/you/.rvm/gems/ruby-1.9.3-p194/gems/origin-1.0.5/lib/origin/mergeable.rb:199:in `prepare'
	from /Users/you/.rvm/gems/ruby-1.9.3-p194/gems/origin-1.0.5/lib/origin/mergeable.rb:158:in `block in __override__'
	from /Users/you/.rvm/gems/ruby-1.9.3-p194/gems/origin-1.0.5/lib/origin/selectable.rb:597:in `block (2 levels) in selection'
	from /Users/you/.rvm/gems/ruby-1.9.3-p194/gems/origin-1.0.5/lib/origin/selectable.rb:596:in `each_pair'
	from /Users/you/.rvm/gems/ruby-1.9.3-p194/gems/origin-1.0.5/lib/origin/selectable.rb:596:in `block in selection'
	from /Users/you/.rvm/gems/ruby-1.9.3-p194/gems/origin-1.0.5/lib/origin/selectable.rb:594:in `tap'
	from /Users/you/.rvm/gems/ruby-1.9.3-p194/gems/origin-1.0.5/lib/origin/selectable.rb:594:in `selection'
	from /Users/you/.rvm/gems/ruby-1.9.3-p194/gems/origin-1.0.5/lib/origin/mergeable.rb:156:in `__override__'
	from /Users/you/.rvm/gems/ruby-1.9.3-p194/gems/origin-1.0.5/lib/origin/selectable.rb:261:in `ne'
	from (eval):2:in `ne'
	from /Users/you/.rvm/gems/ruby-1.9.3-p194/gems/mongoid-3.0.3/lib/mongoid/paranoia.rb:21:in `block in <module:Paranoia>'
....

It might because you are using version 1.0.5 of the origin gem, which was yanked from rubygems.org yesterday: http://rubygems.org/gems/origin/versions/1.0.5

If that’s the case, you’ll probably want to uninstall bad version:
gem uninstall origin -v 1.0.5

If you’re using Rails 3, you’ll want to make sure that your Gemfile.lock does not refer to origin 1.0.5. You can run “bundle update” or delete your Gemfile.lock and run “bundle” to create a new one.

For more information, take a look at the issue on Github. Good luck!