Flowdock

Recent notes

RSS feed
October 26, 2010 - (>= v3.0.0)
0 thanks

Use super to override, and not alias_method_chain

Somehow, If you want to extend the behaviour of attributes=,

alias_method_chain does not work. It simply breaks (could not find out how exactly).

def attributes_with_some_feature=(new_attributes, guard_protected_attributes = true)
  attributes_without_some_feature=(new_attributes, guard_protected_attributes)
end
alias_method_chain :attributes=, :some_feature

this breaks the code. dynamic finders and assignments didn’t work as before (Even though no behaviour has changed yet).

Instead,

def attributes=(new_attributes, guard_protected_attributes = true)
  # custom code
  super(new_attributes, guard_protected_attributes)
end

does work as expected.

I prefer using alias_method_chain for breaking open existing functionality, but in this case it won’t work.

October 26, 2010
1 thank

null to no effects

change_column will not query to replace the null values when you change null to false, even if you have a default set. This may cause the query to fail (may depend on the database used).

change_column_null will optionally take a value to replace nulls if you are setting null to false. If you want to set a default and disallow nulls you likely can’t do both in one change_column call.

October 22, 2010
1 thank

doesn't work directly off a class.

for some reason this method only works on relation objects, not directly on an AR class.

# doesn't work
User.offset(3).limit(1)

# does work
User.limit(1).offset(3)

there’s an closed ticket for this here http://rails.lighthouseapp.com/projects/8994/tickets/5688-modeloffsetxlimitx-unknown-offset-method-exception and should be resolved in the next release of rails.

October 22, 2010
1 thank

still broken

add_index is a different method. I think this is just a bug and it’s broken.

October 21, 2010 - (v3.0.0)
0 thanks

Validate number

option like :greater_than still supported

use like this

Code example

validates :position, :presence => true, :numericality => {:greater_than => 0}

October 20, 2010
4 thanks

use raw() instead

Don’t use this method unless you’re sure your string isn’t nil. Instead use the raw() method, which wont raise an exception on nil.

October 19, 2010
1 thank

Looking for the docs?

Check the ClassMethods – the docs on filters are there.

October 16, 2010 - (>= v3.0.0)
10 thanks

needs to be paired with respond_to

Needs to be paired with respond_to at the top of your class.

class MyController < ApplicationController
  respond_to :js, :html
October 13, 2010
10 thanks

Sending array parameters

Another technique to use when you need to send an array parameter is pass in the :multiple option.

check_box("puppy", "commands", {:multiple => true}, "sit", nil)
check_box("puppy", "commands", {:multiple => true}, "fetch", nil)
check_box("puppy", "commands", {:multiple => true}, "roll_over", nil)

If all checkboxes are checked, the paramters will be:

"puppy" => {"commands" => ["sit", "fetch", "roll_over"]}

NOTE: because of the gotcha, the hidden fields will be inserted and any unchecked boxes will be sent as “” (empty string). You will need to filter those values out in your model:

class Dog < ActiveRecord::Base
  def commands=(commands)
    commands.reject(&:blank?)
  end
end
October 13, 2010 - (v2.1.0 - v3.0.0)
1 thank
October 11, 2010
0 thanks

Useful for mocking out IO methods like #gets and #puts

This class is helpful when testing certain classes of software libraries that are dependent on console input and output, similar to some testing uses of Java’s StringBuffer

October 11, 2010
0 thanks

output is buffered and will not appear until flush

Output is buffered on most operating systems. To override this behavior, force the stdout or other io to sync

STDOUT.sync = true
October 11, 2010 - (>= v3.0.0)
0 thanks
October 11, 2010 - (>= v3.0.0)
1 thank

Use ModelClass.model_name.human

eg. Person.model_name.human will return the i18n name for the model.

see for more info: ActiveModel::Translation

October 9, 2010
4 thanks

Be Advised

Also may convert original string into Jamaican.

e.g.

"green moon".squeeze  #=> "gren mon"
October 7, 2010
1 thank

Preserve order of elements within fields_for

I had the @colleagues collection prepared that I wanted to be rendered within fields_for block. However it was searchlogic object with filtering/sorting applied, and the sort order was not preserved in resultant view.

<%= f.fields_for :evaluators, @colleagues do |builder| %>
<%= render "colleague", :f => builder %>
<% end %>  

Solution to this problem was typecasting this collection to array

<%= f.fields_for :evaluators, @colleagues.to_a do |builder| %>
<%= render "colleague", :f => builder %>
<% end %>  
October 7, 2010 - (>= v3.0.0)
1 thank

Custom validator with i18n support

Here is modified EmailValidator from the example above:

class EmailValidator < ActiveModel::EachValidator
  def validate_each(record, attribute, value)
    record.errors.add(attribute, options[:message] || :email) unless
      value =~ /\A([^@\s]+)@((?:[-a-z0-9]+\.)+[a-z]{2,})\z/i
  end
end

And locale:

en:
  activerecord:
    errors:
      messages:
        email: "is not an email"
October 4, 2010
1 thank

Bind the named method to the receiver

Binds the named method to the receiver, returning a Method object with access to the internals of the receiver, such as self and instance variables.

September 29, 2010
1 thank

Anchor option

It’s not documented, but :anchor is an option.

polymorphic_path(commentable, :anchor => 'comments')

will return:

/article/1#comments
September 29, 2010 - (v3.0.0)
1 thank

Mistake in example for Rails 3

This code doesn’t work:

activemodel:
  attribute:
    post:
      cost: "Total cost"

Everything is OK with this one:

activerecord:
  attributes:
    post:
      cost: "Total cost"
September 27, 2010
0 thanks

Nice german translation independet of structure of a sentence

Eine pragmatische Lösung für das Übersetzungsproblem der Rails Methode distance_of_time_in_words(). Im Deutschen wird je nach Satzbau eine andere Ausgabe benötigt.

Vor mehr als 5 Monaten“/”Vor etwa einem Jahr“ — statt wie im Original ”Dauer: mehr als 5 Monate“/”Dauer: etwa 1 Jahr

http://gist.github.com/598965

September 23, 2010
0 thanks

Or maybe...

or maybe

add_index :user_follows , :user
add_index :user_follows , :followed_user
September 22, 2010
1 thank

About the options argument

The options are not documented, but of course you can use the same options than submit_tag.

Note that all non-documented options are simply passed to the input tag. Amongst other things, this allows you to change the default name attribute (commit):

form.submit 'Cancel', :name => 'cancel'

That’s very handy in forms with multiple submit buttons, this way the controller can easily check in the params which action was submitted.

September 21, 2010
1 thank

using joins, group, having

Code example

named_scope :red, :joins =>   [:color_lis => :color], :group => "color.id", :having => ["color.xx IS NULL"]
September 17, 2010 - (<= v2.3.8)
1 thank

No Layout (fixed typo)

@wiseleyb: Seems to be a typo, should be:

render_to_string(:action => "users/profile", :layout => false)
September 17, 2010
0 thanks
September 16, 2010
1 thank

Re: Doesn't work? Don't think it ever has.

Instead of

create_table :user_follows, :force => true do |t|
  t.references :user
  t.references :followed_user
  t.timestamps
  t.index :user
  t.index :followed_user
end

Try

create_table :user_follows, :force => true do |t|
  t.references :user
  t.references :followed_user
  t.timestamps
end

index :user_follows , :user
index :user_follows , :followed_user

It looks like the provided examples are incorrect…

September 13, 2010 - (>= v1.0.0)
2 thanks

No concurrency

If you want to handle concurrency, this doesn’t work:

a = Article.first
b = Article.first
a.increment!(:view_count)
b.increment!(:view_count)
a.reload.view_count # -> 1
b.reload.view_count # -> 1

Instead, use SQL:

def increment_with_sql!(attribute, by = 1)
  raise ArgumentError("Invalid attribute: #{attribute}") unless attribute_names.include?(attribute.to_s)
  original_value_sql = "CASE WHEN `#{attribute}` IS NULL THEN 0 ELSE `#{attribute}` END"
  self.class.update_all("`#{attribute}` = #{original_value_sql} + #{by.to_i}", "id = #{id}")
  reload
end
September 9, 2010
1 thank

bad idea.

Just a note, ypetya’s idea of using a before filter to set the primary key wont scale. transactions will eventually step on each other and probably end up with duplicate key ids, unless you have some other method to ensure uniqueness.

You’d be better off using mysql to generate the default integer primary key and have a secondary string “key” field.