Flowdock

Recent notes

RSS feed
February 7, 2009 - (>= v2.2.1)
1 thank

Documentation

Good docs can be found here: http://www.artweb-design.de/2008/7/18/the-ruby-on-rails-i18n-core-api

See also: http://rails-i18n.org/wiki for an extensive list of resources.

February 7, 2009 - (>= v2.2.1)
3 thanks

Deprecated

This method is deprecated. You should use:

I18n.translate('activerecord.errors.messages')
February 6, 2009 - (>= v2.1.0)
1 thank

Whacky edge case

The above works great as long as you select the primary key of the owning assocations.

preload_associations calls a group_by on that object so if there is no primary key attributed filled out it will reduce the records to 1 object. ex: rows = foo.find(:all,:select=>“boo.id, foo.name, foo.age, count(DISTINCT foo.id)”, :group=>“foo.name,foo.age having count( DISTINCT foo.id) > 1”,:joins=>“INNER JOIN bar.foo on bar.foo_id = foo.id”)

preload_assications(rows,:bar)

rows.first.bar.name #=> sql call already made in preload rows.last.bar.name #=> just made another sql call to get bar

fix: :select=>“foo.id, boo.id, foo.name, foo.age, count(DISTINCT foo.id)”

now preload_associations will include all the ids found instead of just the 1st one.

February 5, 2009
1 thank

Weird method...

Takes three params:

- a Class constant (has to be an existing class)
- a "tag" param that, if set to "tag:yaml.org,2002:binary" will call unpack("m") on the third parameter, val; any other values for tag are ignored
- val can be a Hash or a String; if it's a string it is wrapped in a hash {'str' => val}, other wise...
  1. an instance of klass is allocated

  2. an instance of string is initialized, with the val parameter, and bound to the class context

  3. for each key in val (if any!), set instance variables in the instantiated class

So, what does this method do, a part from making my eyes hurt? It loads a yaml file and instantiates a class and sets the ivars found in the yaml file. Sorta.

It is probably the worst code I have ever seen in the ruby standard libs. WTF!!

:)

February 4, 2009
1 thank

How I use Optimistic Locking

I have used Optimistic locking often, but usually I only need it in one or two places in the codebase, not everywhere an object is saved whose model has a lock_version column. So what I usually end up doing is using a little module I wrote called OptimisticallyLockable (awesome name right?). Here it is:

module OptimisticallyLockable

  def self.included(receiver)
    receiver.lock_optimistically = false
    receiver.class_eval do

      def self.with_optimistic_locking
        original_lock = self.lock_optimistically
        self.lock_optimistically = true

        begin
          yield
        ensure
          self.lock_optimistically = original_lock
        end
      end

    end
  end

end

When included in a model that has a lock_version column it will turn off optimistic locking. Then when you want to actually use optimistic locking you can just use the with_optimistic_locking method like this:

class Blog
   include OptimisticallyLockable

   def do_something_destructive!
     self.class.with_optimistic_locking do
        #  do something important here
     end
   end                                
end
February 4, 2009
1 thank

RE: Careful when building gems

I found out a way to combine using RDoc::usage when you are building a gem. By ripping out the code from the usage method you can create your own version which opens the correct file.

In my case, I skipped the file reading and just put the usage information in a string and used that directly.

Here is my code:

$usage = %Q{
 = Synopsis
 ...
 = Usage
 ...

 == Options
 ...
 }

 # Shamefully stolen from RDoc#usage. We cannot use RDoc::usage because
 # RubyGems will call this from a wrapper, and #usage is hardcoded to look
 # at the top-level file instead of the current one. I have changed this
 # code to instead just parse a string.
 def usage_and_exit!
   markup = SM::SimpleMarkup.new
   flow_convertor = SM::ToFlow.new

   flow = markup.convert($usage, flow_convertor)

   options = RI::Options.instance
   formatter = options.formatter.new(options, "")
   formatter.display_flow(flow)

   exit(0)
 end

Look in usage_no_exit if you want to rip stuff out. It’s up to you how and if you implement this at all, but it’s a shortcut to use the RDoc code and formatting. Do also consider doing the formatting yourself by hand and just output that string instead.

February 4, 2009
0 thanks
February 4, 2009
3 thanks

Multiline regexps

A shortcut for multiline regular expressions is

/First line.*Other line/m

(notice the trailing /m)

For example:

text = <<-END
  Hello world!
  This is a test.
END

text.match(/world.*test/m).nil?  #=> false
text.match(/world.*test/).nil?   #=> true
February 4, 2009
0 thanks

usage example

code

class MyModel < ActiveRecord::Base
  def created_today?
    self.created_on.to_date == Date.today
  end
end
February 4, 2009
0 thanks

Careful when building gems

If you are building a gem with executables and you think about using RDoc::Usage for facilitating the --help message, think again.

usage and usage_no_exit is hardcoded to look for the initial comment in the top level file being executed, which is normally fine, but when installing a gem, RubyGems will generate a wrapper executable for you, and usage will therefore look in that wrapper file for the comment instead of your own file.

The methods contain too much code to be easily monkey patched too. Hopefully, this will be fixed in a later version.

February 3, 2009
3 thanks

Possible gotcha

Please note that exists? doesn’t hold all the conventions of find, i.e. you can’t do:

Person.exists?(:conditions => ['name LIKE ?', "%#{query}%"]) # DOESN'T WORK!
February 3, 2009
0 thanks

Getting functionality from instances

If you want to get this functionality from instances of the models too, you can easily monkey patch rails to allow this. This is only semi-bad practice, AFAIK.

In config/initializers/overrides.rb:

#
# Wrapper for @model.human_attribute_name -> Model.human_attribute_name
#
class ActiveRecord::Base
  def human_attribute_name(*args)
    self.class.human_attribute_name(*args)
  end
end

Now, why is this bad? Because we change a core class, and that makes maintainability a little bit harder since new developers will not know about this.

The good part is that is such a small thing and as long as human_attribute_name exists in the class, this extension will work.

Example usage:

# index.html.haml
%th= User.human_attribute_name('login')
%th= User.human_attribute_name('email')
# ...

# show.html.haml
%p
  %strong= "#{@user.human_attribute_name('login')}: "
  = @user.login

In this example, about nothing was gained at all, really. A better example is when you are building helpers to do stuff like displaying model attributes for you and whatnot. Examples for this would be far too huge to show off here, but basically, you avoid having to do stuff like this:

if options.include? :model
  model = options[:model]
  model = model.class unless model.is_a? Class
  model.human_attribute_name(field)
else
  # ...
end

and you want to keep your views clean (@user vs. @user.class)

February 3, 2009
3 thanks

Nothing here

You’re probably looking for I18n::Backend::Simple.

February 3, 2009
4 thanks

This method will still rewrite all the values of the table

Even if you update only a small boolean flag on your record, update_attribute will generate an UPDATE statement that will include all the fields of the record, including huge BLOB and TEXT columns. Take this in account.

February 2, 2009
1 thank

usage

code

@items = Item.find(:all)
@items.should have_at_least(1).item
February 1, 2009 - (v2.2.1)
3 thanks

You can't use Symbols, but you can use Regexps

You can’t use Symbol (although Symbol is accepted with render :action => :new), like:

assert_template :new # WON'T WORK!

But you can use Regexp, e.g.:

assert_template /new/ # WORKS OK

Note that the String matched with your Regexp is the full path to the template relative to the view/ directory of your app, so this will not work:

assert_template /^new$/ # WON'T WORK!

However this might:

assert_template /^employees\/new.html.haml$/
January 30, 2009 - (v1.2.0 - v2.1.0)
3 thanks

Hash conditions require explicit key and value

When condition passed as hash, the behavior is different from a finder method. Finder methods, such as:

find(:all, :user=>user)

will apply the user_id = user.id convention, provided user is an association (e.g. belongs_to :user). The exists? method will not do the same. You must specify the foreign key name and value explicitly, i.e:

exists?(:user_id=>user.id)
January 27, 2009 - (>= v2.2.1)
5 thanks

Getting the object in a partial

If you need to get the object for the form inside a partial, and can’t use the instance variable, use the #object method… This is particularly useful when you’re dealing with single-table inheritance subclasses (e.g. MyOtherClass inherits from MyClass) or when you are using the same partial across different controllers.

new.html.erb

<% form_for(@my_object) do %>
  <%= render :partial => 'form' %>
  <%= submit_tag 'Create' %>
<% end %>

_form.html.erb

<% if f.object.class.is_a? MyClass %>
 <%# do something... %>
<% elsif f.object.is_a? MyOtherClass %>
  <%# do something else... %>
<% end %>
January 27, 2009
1 thank

Add Rspec files to the annotations

By default the annotations search the ‘test’ folder, but not the ‘spec’ folder if you are using Rspec. To get those specs involved do this:

require 'source_annotation_extractor'

class SourceAnnotationExtractor
  def find(dirs=%w(app lib spec))
    dirs.inject({}) { |h, dir| h.update(find_in(dir)) }
  end
end

If you have other folders you want to check, just add them to the dirs list.

January 27, 2009 - (v2.1.0 - v2.2.1)
1 thank

Description

Similar to Ruby’s built-in attr_writer, only it creates a class attribute writer method (as opposed to an instance attribute writer method).

January 27, 2009 - (v2.1.0 - v2.2.1)
2 thanks

Description

Similar to Ruby’s built-in attr_reader, only it creates a class attribute reader method (as opposed to an instance attribute reader method).

January 27, 2009
5 thanks

Use collect in nested content_tags

Remember to use #collect instead of #each in nested content_tags

arr = ['a','b','c']
content_tag :div do 
  arr.collect { |letter| content_tag(:scan, letter) 
end
#=> <div>
#      <scan>a</scan>
#      <scan>b</scan>
#      <scan>c</scan>
#   </div>

If you used #each you would get this (which is probably a mistake):

#=> <div>
#      abc
#   </div>
January 26, 2009
5 thanks

two ways to disable single table inheritance

  1. Don’t use the column name ‘type’

  2. Or if the first is no option for you: Tell Rails to look for a not existing column like:

class MyModel < ActiveRecord::Base

  # disable STI
  inheritance_column = :_type_disabled
end  
January 26, 2009 - (>= v2.2.1)
3 thanks

alternative (working with 2.2.X)

ActionController::Base.relative_url_root

January 25, 2009
3 thanks

Routes = RouteSet.new

In config/routes.rb you can see this:

ActionController::Routing::Routes.draw do |map|
  #routes
end

If you want to look at the code in ActionController::Routing you won’t find the definition of Routes. That’s because it’s actually an instance of the class RouteSet, defined in action_controller/routing.rb

Routes = RouteSet.new
January 24, 2009
8 thanks

How to test different responses of respond_to

You can shorten this:

@request.env['HTTP_ACCEPT'] = "application/rss"

To this:

@request.accept = "application/rss"

Also, if you send more than one Mime type, it will render the first one:

@request.accept = "text/javascript, text/html" #=> renders JS
@request.accept = "text/html, text/javascript" #=> renders HTML
January 24, 2009
0 thanks

Adding "alt" text to the image tag

<%= image_submit_tag (“create.gif”, :alt => “Create new entity”) %>

This way when the images are disabled or don’t work you get the nice custom text instead of the standard one. Pretty useful.

January 23, 2009
1 thank

Alternate for Rails 2.0

Obviously these methods are protected so usage in an app is discouraged. But if you need to use it anyway for some reason Rails 2.0 also has sanitize_sql_for_conditions which operates exactly like sanitize_sql used to (i.e. it determines if it needs to be processed as an array or hash). So if you are going to blow by the protected status might as well use the easier version. :)

January 22, 2009
2 thanks

Correct way to quote for the shell

A followup for my previous comment;

I actually found a good way to handle quoting for the shell in Ruby 1.9 in case you really need to (for example to pipe the output from the examples I gave below).

require 'shellwords'

escape = lambda { |str| Shellwords.shellescape(str) }
file = %(Peter "Smiley" McGraw.txt)
puts "grep foobar #{escape[file]} > foobars"
  # => grep foobar "Peter \"Smiley\" McGraw.txt" > foobars

Do note that I have not tested this since I do not have Ruby 1.9 installed, but from what I have read, this should work properly there.

I still do not know a good way to do this in Ruby 1.8.