Flowdock

Recent notes

RSS feed
April 21, 2009
3 thanks

To throw an exception, use Kernel#raise

Other languages use the term throw for raising exceptions, but Ruby has a specific raise call for that.

April 21, 2009
7 thanks

Do not forget to add indexes

Don’t forget to add indexes to HATM table:

add_index :developers_projects, [:developer_id, :project_id]
April 21, 2009
1 thank

Merges with inherited values from super class

http://www.spacevatican.org/2008/8/19/fun-with-class-variables

“When you set a class_inheritable_array or a class_inheritable_hash you are actually concatenating (or merging) with the value inherited from the super class.”

Code example

class Base
  class_inheritable_hash :attrs
  self.attrs = {:name => 'Fred'}
end

class Derived < Base
  self.attrs = {:export => 'Pain'}
end

Derived.attrs #=> {:name => 'Fred', :export => 'Pain'}
April 21, 2009 - (>= v2.3.2)
5 thanks

strip_tags method not functioning in controllers, models, or libs

It comes up with an error about white_list_sanitizer undefined in the class you’re using it in. To get around this, use:

ActionController::Base.helpers.strip_tags('string')

To shorten this, add something like this in an initializer:

class String
  def strip_tags
    ActionController::Base.helpers.strip_tags(self)
  end
end

then call it with:

'string'.strip_tags
April 21, 2009 - (>= v2.3.2)
3 thanks

sanitize method not functioning in controllers, models, or libs

It comes up with an error about white_list_sanitizer undefined in the class you’re using it in. To get around this, use:

ActionController::Base.helpers.sanitize('string')

To shorten this, add something like this in an initializer:

class String
  def sanitize
    ActionController::Base.helpers.sanitize(self)
  end
end

then call it with:

'string'.sanitize
April 20, 2009
2 thanks

Cycle with first and last

I needed a cycle that was also aware of the first and last items in the collection. This is adapted from a snippet I found while Googling:

def cycle_with_first_last(object, collection, options = { })
  addition = ""
  addition += " #{options[:first]}" if object == collection.first
  addition += " #{options[:last]}"if object == collection.last
  cycle(options[:odd], options[:even]) + addition
end

Just put that in your helpers…

April 16, 2009
1 thank

Extracting the First Element

To extract the first element from an Array, use shift:

array = [ 1, 2, 3 ]           # => [ 1, 2, 3 ]
array.first                   # => 1
array                         # => [ 1, 2, 3 ]
array.shift                   # => 1
array                         # => [ 2, 3 ]
April 16, 2009
1 thank

Extracting the Last Element

To remove the last element from the Array, use pop:

array = [ 1, 2, 3 ]           # => [ 1, 2, 3 ]
array.last                    # => 3
array                         # => [ 1, 2, 3 ]
array.pop                     # => 3
array                         # => [ 1, 2 ]
April 16, 2009
12 thanks

Parameters for Hash#inject

When running inject on a Hash, the hash is first converted to an array before being passed through.

The typical Enumerable#inject approach would be to simply capture the value:

array.inject(...) do |c, v|
end

In the case of a Hash, v is actually a key/value pair Array. That is the key is v.first and the value is v.last, however using the pair this way is awkward and can lead to confusion.

Better to simply expand the parameters in the block definition:

hash.inject(...) do |c, (k, v)|
end

Where c is the traditional carry variable and k/v represent key and value respectively.

April 16, 2009 - (>= v2.0.0)
2 thanks

Example

This function can be used to pass the ID of selected item, for example:

# with select or collection_select helpers:
{ :onchange => remote_function(:url => { :action => 'do_smth' }, :with => "'id=' + $('the_id').value") }

# and grab ID in controller action as usually: 
YourModel.find(params[:id])
April 16, 2009
3 thanks

Various use cases

Example

user = User.new
user.name = 'Akhil Bansal'
user.save

user =  User.new(:name => 'Akhil')
user.save

User.new do |u|
  u.name = 'Akhil'
  u.save
end
April 16, 2009
0 thanks

Known unknowns

In case it isn’t obvious - this is what you use when you’re fleshing out all the tests that you haven’t written yet. eg if you have a set of twenty tests for a complex piece of functionality, and just want to write out the “should” declarations (or equivalent), so you don’t forget all the corner cases… then fill out the tests themselves. Putting an assert_fail makes sure you notice if you forget to come back and fill in the body of a test.

April 15, 2009 - (>= v2.3.2)
0 thanks

Testing HTTP Digest authentication

Testing HTTP Digest authentication is a bit tricky. I wrote a post describing how to accomplish it.

http://lightyearsoftware.com/blog/2009/04/testing-http-digest-authentication-in-rails/

Note also that Digest auth is broken for REST actions using PUT or DELETE. There is an open Lighthouse ticket for this, #2490:

rails.lighthouseapp.com/projects/8994/tickets/2490-http-digest-auth-uses-wrong-request-method-for-put-delete

April 15, 2009
0 thanks

Using global $! to address exception

@noxyu3m: Your code is actually syntactically wrong. The global is called $!

Your code should have been:

def create
  @model = Model.new(params[:model)
  @model.save!
rescue
  logger.error($!.to_s)
end

Although I would prefer

def create
  @model = Model.new(params[:model)
  @model.save!
rescue ActiveRecord::RecordInvalid
  logger.error($!.to_s)
end

to only catch expected exceptions, just like the documentation proposed.

April 14, 2009 - (v2.2.1 - v2.3.2)
2 thanks
April 14, 2009
0 thanks

Re: Force initial value

An alternative to @eric_programmer’s would be to extract it entirely from the controller logic…

class Person
  def sender
    self[:sender] || 'contact@host.com'
  end
end

There are a ton of ways to do it, but making this a business logic decision will let you get the same logic from any possible implementation angle. Scripts, web service, etc.

April 12, 2009
1 thank

To find a tag with an id or class

assert_select ‘td.highlight’, { :count => 2 }

finds 2 td tags with the highlight class.

assert_select ‘div#special’

finds div with id=special

April 12, 2009
0 thanks

Takes attribute as a symbol

Attribute must be passed as a symbol:

User.toggle(:funny)

not

User.toggle(funny)
April 9, 2009
0 thanks

Deprecation warning for old-style options

You will get a warning if you don’t define your separators as a hash:

DEPRECATION WARNING: number_with_delimiter takes an option hash instead of separate delimiter and precision arguments

So while you can still use that style, it’s not without a scolding.

April 9, 2009
1 thank

Outside of app code

How do I call this from script/console?

April 9, 2009
11 thanks

Define handlers in order of most generic to most specific

The later the definition of the rescue handler, the higher the priority:

rescue_from Exception, :with => :error_generic
rescue_from Exception::ComputerOnFire, :with => :panic

Declaring the Exception catch-all handler last would have the side-effect of precluding any other handlers from running.

This is what is meant by being “searched…from bottom to top”.

April 9, 2009
4 thanks

Method has moved to ActionController::Rescue::ClassMethods module

This method has simply moved, still works the same way in 2.3+

New location: ActiveSupport::Rescuable::ClassMethods#rescue_from

April 9, 2009
1 thank

Like select_values for multiple values

The names are somewhat confused:

Model.connection.select_values("SELECT id,name FROM users") => ["1","2","3"]
Model.connection.select_rows("SELECT id,name FROM users") => [["1","amy"],["2","bob"],["3","cam"]]
April 9, 2009
1 thank

select_values returns Strings for MySQL

This method will return all values as strings from MySQL. It is easy to convert if required, for example, to integers:

select_values("SELECT id FROM companies LIMIT 3") => ['1','2','3']
select_values("SELECT id FROM companies LIMIT 3").collect(&:to_i) => [1,2,3]
April 8, 2009
2 thanks

use create table :force => true

if you want to drop a table before creating one in a migration, use the :force => true option of the create_table method

April 8, 2009 - (>= v2.3.2)
13 thanks

Setting child_index while using nested attributes mass assignment

When using nested attributes mass assignment sometimes you will want to add new records with javascript. You can do it with pure javascript, but if HTML is long your javascript will be long and messy and it will not be DRY as probably you already have a partial for it.

So to add a partial dynamically you can do something like that (notice string “index_to_replace_with_js”):

link_to_function

def add_object_link(name, form, object, partial, where)
  options = {:parent => true}.merge(options)
  html = render(:partial => partial, :locals => { :form => form}, :object => object)
  link_to_function name, %{
    var new_object_id = new Date().getTime() ;
    var html = jQuery(#{js html}.replace(/index_to_replace_with_js/g, new_object_id)).hide();
    html.appendTo(jQuery("#{where}")).slideDown('slow');
  }
end

js method in one of helpers (from minus mor plugin)

def js(data)
  if data.respond_to? :to_json
    data.to_json
  else
    data.inspect.to_json
  end
end

This method will generate link adding generated partial to html.

The thing that is not mentioned in docs is how to set child_index. You must add it as an argument in hash.

Example of partial

<% form.fields_for :tasks, task, :child_index => 
       (task.new_record? ? "index_to_replace_with_js" : nil) do |tasks_form| %>
  <% tasks_form.text_field :name %>
<% end %>

Using add_object_link

<% form_for :project do |form| %>
  <div id="tasks">
    <%# displaying existing tasks %>
  </div>

  <%= add_object_link("New task, form, Task.new, "task", "#tasks") %>

<% end %>

Thanks to child_index after insertion it will change indexes to current time in miliseconds so added tasks will have different names and ids.

April 8, 2009 - (>= v2.2.1)
1 thank

Translations of label method

The label method won’t use your translated attribute names - which seems like big disadvantage of this method.

For a quick workaround, try using this in a helper:

def label(object_name, method, text = nil, options = {})
  text ||= object_name.classify.constantize.human_attribute_name(method.to_s)
  ActionView::Helpers::InstanceTag.new(object_name, method, self, 
    options.delete(:object)).to_label_tag(text, options)
end

I didn’t properly test this, but it seems to work.