Flowdock

Recent notes

RSS feed
November 3, 2009
0 thanks

Setting a custom Content type

The given example seems to be broken. The :mime_type option as well as the [] access on the Mime::Type class are both not working.

The following code allows the custom setting of content types as intended by the original example:

class  PostsController < ActionController::Base
  def show
     @post = Post.find(params[:id])

    respond_to do |format|
      format.html
      format.ics { render :text => post.to_ics, :content_type => Mime::Type.lookup("text/calendar")  }
      format.xml { render :xml => @people.to_xml }
    end
  end
end
November 2, 2009
0 thanks

To use the memcached gem

If you use the mem_cache_store it will use “memcache-client” to talk to the actual cache. memcache-client is a pure Ruby library that is bundled with rails. There is a Ruby/C library called “memcached” that uses native bindings to talk to memcache, and it is reportedly (http://blog.evanweaver.com/files/doc/fauna/memcached/files/README.html) up to a 100 times faster than memcache-client. To use that instead,

# in shell
$ sudo gem install memcached --no-rdoc --no-ri

# in config/production.rb
require 'memcached'
config.action_controller.cache_store =
  :mem_cache_store, Memcached::Rails.new("localhost:11211")

This feature (to pass a configured MemCache-like object to cache_store=) is available since rails 2.3.3 and will hopefully be documented in 2.3.5.

October 31, 2009
2 thanks

Don't forget to require 'tmpdir'

If you simply say Dir.tmpdir you might get a nice surprise:

irb> Dir.tmpdir
NoMethodError: undefined method `tmpdir' for Dir:Class

from (irb):1

Strangely, this method seems to be stored in a file that Ruby doesn’t require by default. Just require 'tmpdir' and all should be well.

irb> require 'tmpdir'
=> true
irb> Dir.tmpdir
=> "/var/folders/An/AnwlXPZFH2aRLCERERQDKE+++TI/-Tmp-"
October 30, 2009
7 thanks

How FormBuilders work

What, you were expecting documentation? :)

An excellent survey of how FormBuilders work is here:

http://code.alexreisner.com/articles/form-builders-in-rails.html

October 30, 2009
3 thanks

Map-like Manipulation of Hash Values

Let’s say you want to multiply all values of the following hash by 2:

hash = { :a => 1, :b => 2, :c => 3 }

You can’t use map to do so:

hash.map {|k, v| v*2 }   # => [6, 2, 4]

However, with merge you can:

hash.merge(hash) {|k,v| v*2 }   => {:c=>6, :a=>2, :b=>4}

(The above is Ruby 1.8, in Ruby 1.9 the order is preserved.)

October 30, 2009
0 thanks

Outputs name even if condition is false

Please note that if the condition is false, link_to_if will still output the name given as a plain text (as documented above). If you want nothing printed at all, you’ll have to stay with the old and trusty:

link_to "Login", ... if @current_user.nil?
October 30, 2009
2 thanks

Outputs name even if condition is false

Please note that if the condition is false, link_to_if will still output the name given as a plain text (as documented above). If you want nothing printed at all, you’ll have to stay with the old and trusty:

link_to "Login", ... if @current_user.nil?
October 28, 2009
7 thanks

#blank?

The opposite of this is #blank?

October 27, 2009
4 thanks

#present?

The opposite of this is #present?

October 27, 2009 - (>= v1.0.0)
1 thank

Only works within a transaction

Of course, this has to be done in a transaction, like so:

# we've loaded user earlier and did some checks which took some time
# to make sure, updates made meanwhile by other threads don't lead to
# optimistic locking errors here, we do this when finally suspending
User.transaction do
  user.lock!
  user.suspended = 1
  user.save!
end
October 23, 2009
2 thanks

Setting child_index while using nested attributes mass assignment with prototype

First of all, drogus idea really helped me. I’m not using jQuery, therefore I implemented my own version:

link_to_function

def add_object_link(name, where, render_options)
  html = render(render_options)

  link_to_function name, %{
    Element.insert('#{where}', #{html.to_json}.replace(/index_to_replace_with_js/g, new Date().getTime()));
  }
end

Using add_object_link

<%= add_object_link 'Add asset', 'assets', :partial => 'assets/asset', :object => Asset.new, :locals => { :f => f } %>
October 22, 2009 - (>= v2.1.0)
4 thanks

Update statement won't include all attributes with ActiveRecord::Dirty

With the addition of ActiveRecord::Dirty, the update statement will only feature changed columns, as opposed to the comment of railsmonk below.

October 20, 2009
3 thanks

See Dir#glob

See glob for more usage information and comments.

October 20, 2009
2 thanks

Getting relative path from absolute globbing

Say you want to scan for files in directory base_dir and you want to use the relative path from this base dir, you could do it like this:

base_dir = '/path/to/dir'
files = Dir[File.join(base_dir, '**', '*.yml')]

# files now contain absolute paths:
files.first # => "/path/to/dir/foo/bar.yml"

# let's make them relative
base_pathname = Pathname.new(base_dir)
files = files.collect do |file|
  Pathname.new(file).relative_path_from(base_pathname)
end

files.first # => "foo/bar.yml"

Of course, a more common use-case could be the following:

def scan_for_documents!
  base_path = Pathname.new(self.base_path)
  self.contained_files = []
  Dir[File.join(self.base_path, '**', '*.pdf')].each do |full_path|
    path = Pathname.new(full_path).relative_path_from(base_path)
    self.contained_files << path
  end
end
October 19, 2009
1 thank

Get all inner texts

Extend REXML::Element so that it can get the first text and following inner texts (child texts included) of the current element as array and as string:

class REXML::Element

 def inner_texts
  REXML::XPath.match(self,'.//text()')
 end

 def inner_text
  REXML::XPath.match(self,'.//text()').join 
 end

end
October 18, 2009
1 thank

Receiving data over UDP

It’s perfectly normal to receive ‘X’ strings with Ruby’s UDP sockets before the actual content.

Consider the following example:

require 'socket'

PORT = 5500

socket = UDPSocket.new
socket.bind('', PORT)

for i in 1..10
  IO.select([socket])
  p socket.recvfrom_nonblock(4096)
end

Now, sending data with netcat:

echo "Hello APIdock" | nc -vv -u 127.0.0.1 5500

The application would output:

["X", ["AF_INET", 61755, "localhost", "127.0.0.1"]]
["X", ["AF_INET", 61755, "localhost", "127.0.0.1"]]
["X", ["AF_INET", 61755, "localhost", "127.0.0.1"]]
["X", ["AF_INET", 61755, "localhost", "127.0.0.1"]]
["Hello APIdock\n", ["AF_INET", 61755, "localhost", "127.0.0.1"]]
October 17, 2009
1 thank

Re: Passing parameters to before_filter

I am not sure I get your “method 1” alec-c4; won’t that define the method each time the before_filter is called? Why not just define the method in the controller?

You can pass parameters or call protected methods with instance_eval:

before_filter :only => :show do |controller|
  controller.instance_eval do
    redirect_to edit_object_path(params[:id])
  end
end
October 16, 2009 - (>= v2.1.0)
1 thank

No numbers or symbols

“Kyle”, “Дети”, “Niños”, “Quan-lu”, “た ち”

validates_format_of :first_name, :with => /^([^\d\W]|[-])*$/
October 15, 2009
4 thanks

Have check_box checked by default

In addition to comment below, you can make a column with default value so in your forms it will be enabled by default and behave correctly with validation errors unlike :checked => true

in your migration

add_column :accounts, :ssl_enabled, :boolean, :default => 1
October 15, 2009
2 thanks
October 14, 2009
2 thanks

build_association deletes existing dependent record

Surprisingly (at least I was surprised), when an associated record exists, the build_association method immediately NULLs the foreign key in the database.

So if you write a singleton “new” action for the association in the obvious way (calling build_association), then just visiting the page will disconnect an existing associated record. This violates the principle that a GET request shouldn’t affect the database.

To avoid this, you can check for an existing association first, and redirect to the show action.

October 12, 2009
0 thanks

Use it to solve FixtureClassNotFound errors.

If you are using a non standard table name by means of set_table_name in your model:

class MyClassName < ActiveRecord::Base
  set_table_name "mytablename"
end

then you will get FixtureClassNotFound errors when you try to use fixtures in you unit tests. To solve this use set_fixture_class inside your test:

require 'test_helper'
class MyClassNameTest < ActiveSupport::TestCase
  set_fixture_class :mytablename => MyClassName  
end

and rename your fixture file to mytablename.yml

October 10, 2009
2 thanks

Example

[5,6,7].each_with_index do |x,i|

puts "#{i} -> #{x}"

end

Outputs: 0 -> 5 1 -> 6 2 -> 7

October 9, 2009
0 thanks

Case-insensitive comparison

For a case-insensitive comparison, use String#casecmp

October 7, 2009
4 thanks

Hash#without

Here’s a small helper for doing the “opposite” of this method:

class Hash
  def without(*keys)
    cpy = self.dup
    keys.each { |key| cpy.delete(key) }
    cpy
  end
end

h = { :a => 1, :b => 2, :c => 3 }
h.without(:a)      #=> { :b => 2, :c => 3 }
h.without(:a, :c)  #=> { :b => 2 }
October 7, 2009
3 thanks

Streaming XML with Builder

To generate larger XMLs, it’s a good idea to a) stream the XML and b) use Active Record batch finders.

Here’s one way of doing it:

def my_action
  @items = Enumerable::Enumerator.new(
    Item.some_named_scope,
    :find_each,
    :batch_size => 500)

  respond_to do |format|
    format.xml do
      render :text => lambda { |response, output|
        extend ApplicationHelper

        xml = Builder::XmlMarkup.new(
          :target => StreamingOutputWrapper.new(output),
          :indent => 2)
        eval(default_template.source, binding, default_template.path)
      }
    end
  end
end

The Builder template does not need to be modified.

October 5, 2009
1 thank

Using argument version in ruby < 1.8.7

The argument to this method was added in Ruby 1.8.7. If you want to use this form in an earlier version, you must instead use the slice! method.

It is mentioned up in the docs, but here it is again for reference:

# Ruby >= 1.8.7
p = list.pop(n)

# Ruby < 1.8.7
p = list.slice!(-n, n)
October 5, 2009
3 thanks

collect/map

If you’d like to use this method for something like Enumerable#collect, you are looking at the wrong place. This method will return the initial integer, not the values from the block.

a = 20.times { |n| n * 2 } #=> 20

Instead, use Range#collect:

a = (0...20).collect { n * 2 }
October 5, 2009
3 thanks

Use camelize with singular words

To make the business example work, use camelize instead of classify:

"business".camelize     # => "Business"