Notes posted to Ruby on Rails

RSS feed
October 25, 2008
2 thanks

Alternative: use 1000.humanize

1.humanize == “1″ 1000000.humanize == “1.000.000″ 1000.12345.humanize == “1.000,12″

http://pragmatig.wordpress.com/2008/10/25/numbers-for-humans-humanize-for-numeric/

October 24, 2008
1 thank

module includes with callbacks

If you write a plugin or module that includes callbacks make sure to define the method and call super after you’re done with your business.

module CoolStuff

def self.included(base) super base.extend(ClassMethods) # the next line seems to clobber. instead opt for defining an inheritable method # base.after_save :chill end module ClassMethods # cool class methods end def chill self.cool = true end def after_save self.chill super # if you don't call super, bloggy won't run end 

end # yes I know this next line is a divisive issue but it’s common enough ActiveRecord::Base.send :include, CoolStuff

class Blog < ActiveRecord::Base

after_save :bloggy def bloggy slugify_title end 

end

October 24, 2008
13 thanks

Prompt vs. Select

According to the docs in form_options_helper.rb

:include_blank - set to true or a prompt string if the first option element of the select element is a blank. Useful if there is not a default value required for the select element.

:prompt - set to true or a prompt string. When the select element doesn’t have a value yet, this prepends an option with a generic prompt – “Please select” – or the given prompt string.

The main difference is that if the select already has a value, then :prompt will not show whereas the :include_blank always will.

October 24, 2008
1 thank

Styling question

How do we style the select boxes and “:” somehow within this method?

Follwup: it seems in Rails 2.1, FormBuilder#time_select didn’t pass html_options to this method. and it’s fixed i

October 24, 2008
10 thanks

Back it up with a unique index

As mentioned briefly above, as well as using this validation in your model you should ensure the underlying database table also has a unique index to avoid a race condition.

For example:

class User < ActiveRecord::Base validates_uniqueness_of :login_name end 

The index can be specified in the migration for the User model using add_index like this:

add_index :users, :login_name, :unique => true 

You do a similar thing when using the :scope option:

class Person < ActiveRecord::Base validates_uniqueness_of :user_name, :scope => :account_id end 

Should have a migration like this:

add_index :people, [ :account_id, :user_name ], :unique => true 

Note that both the attribute being validated (:user_name) and the attribute(s) used in the :scope (:account_id) must be part of the index.

For a clear and concise explanation of the potential for a race condition see Hongli Lai’s blog.

October 24, 2008
2 thanks

The human side of inflections

Rails 2.2 moves this functionality to the Inflector::Inflections class:

See the ticket and the code that allow the humanisation rules to be centralised in an app.

October 23, 2008
2 thanks

Customizing attribute names in error messages

This can be used to customize attribute names in error messages. See my note in ActionView::Helpers::ActiveRecordHelper#error_messages_for.

October 23, 2008
8 thanks

Customizing attribute names in error messages

By default, the error messages translate the names of the attributes through String#humanize. The way to to change that is to override the ActiveRecord::Base.human_attribute_name method.

For example, if you want to name a column in your database as :www_url and you want to say “Website” instead of “Www url” in the error message, you can put this into your model:

class Person < ActiveRecord::Base def self.human_attribute_name(attribute_key_name) if attribute_key_name.to_sym == :www_url "Website" else super end end end 

Currently this seems to be the cleanest and easiest way. Unfortunately, human_attribute_name is deprecated and may stop working in a future release of Rails.

October 22, 2008
10 thanks

Gotcha when defining :finder_sql or :counter_sql

When setting custom SQL statements in the :finder_sql or :counter_sql queries, if you need to inject attributes from the current object, such as the ID, make sure to disable string interpolation of the statement by using single quotes or %q().

Example:

has_many :relationships, :class_name => 'Relationship', :finder_sql => %q( SELECT DISTINCT relationships.* FROM relationships WHERE contact_id = #{id} ) 

Surrounding this SQL with double-quotes or %Q() will expand #{id} too early, resulting in a warning about Object#id being deprecated and general brokenness.

October 22, 2008 - (>= v2.1.0)
2 thanks

HABTM relation

When you want to create a has_and_belong_to_many relation (og just a has_many :through) use this setup.

Example
class CreateCourses < ActiveRecord::Migration def self.up create_table :seasons do |t| t.integer :year t.string :period end create_table :courses do |t| t.string :courseCode end create_table :courses_seasons, :id => false do |t| t.references :course, :null => false t.references :season, :null => false end add_index :courses_seasons, [:course_id, :season_id], :unique => true end def self.down drop_table :seasons drop_table :courses drop_table :courses_seasons end end 
October 22, 2008
2 thanks

Regenerate the JavaScript after each RJS call

I had a sortable_element that was also a drop_receiving_element. After an element was dropped onto this div, an RJS action refreshed the div with the new elements. The div expanded with these new elements, but the sortable portion remained the same size.

To correctly be able to reorder elements after an Element.update call (from an RJS action or wherever), you need to include a second call to Sortable.create in your RJS view (or other JavaScript), using sortable_element_js or whatever method you please.

October 21, 2008
5 thanks

Using a Loading Graphic

If you want to make a little loading graphic, typically you use an animated gif (like a little spinner or something). Both link_to_remote and remote_form_for allow you to easily do this by using the :loaded and :loading triggers to call javascript.

For example:

<% remote_form_for @survey, :loading => "$('loading').show();", :loaded => "$('loading').hide();" do |f| %> <%= submit_tag ' Save' %> <%= image_tag "indicator_circle.gif", :style => 'display: none;', :id => 'loading' %> <% end %> 

The ‘loading’ parameter used for the ‘$’ prototype selector is the id of the animated gif. It starts out hidden, and is toggled by the loading/loaded triggers.

October 20, 2008
3 thanks

number_to_euro

in small cells:

12--> 12def number_to_euro(amount) number_to_currency(amount,:unit=>'').gsub(' ',nbsp) end
October 18, 2008
0 thanks

Single Table Inheritance and Fixtures

All entries for fixtures for classes derived from the base class must go into the fixture file of the base class. Also, their type must be set. Example fixture:

company_one: name: My Company firm_one: name: A Firm type: Firm priority_client_with_p1: name: SuperVIPClient type: PriorityClient priority: 1
October 16, 2008
0 thanks

Only error message

<%= error_messages_for :order, :header_message => nil, :message => nil %>

Browser view code

<div id=“errorExplanation” class=“errorExplanation”>

 <ul> <li>Weight 只有 1000.0</li> <li>Volume 只有 10.0</li> </ul> </div>
October 15, 2008
29 thanks

List of status codes and their symbols

Note that the :status option accepts not only an HTTP status code (such as 500), but also a symbol representing that code (such as :created), if that makes more sense to you. Here’s a list of which symbols map to which numbers (derived from ActionController::StatusCodes::SYMBOL_TO_STATUS_CODE):

100 = :continue 101 = :switching_protocols 102 = :processing 200 = :ok 201 = :created 202 = :accepted 203 = :non_authoritative_information 204 = :no_content 205 = :reset_content 206 = :partial_content 207 = :multi_status 226 = :im_used 300 = :multiple_choices 301 = :moved_permanently 302 = :found 303 = :see_other 304 = :not_modified 305 = :use_proxy 307 = :temporary_redirect 400 = :bad_request 401 = :unauthorized 402 = :payment_required 403 = :forbidden 404 = :not_found 405 = :method_not_allowed 406 = :not_acceptable 407 = :proxy_authentication_required 408 = :request_timeout 409 = :conflict 410 = :gone 411 = :length_required 412 = :precondition_failed 413 = :request_entity_too_large 414 = :request_uri_too_long 415 = :unsupported_media_type 416 = :requested_range_not_satisfiable 417 = :expectation_failed 422 = :unprocessable_entity 423 = :locked 424 = :failed_dependency 426 = :upgrade_required 500 = :internal_server_error 501 = :not_implemented 502 = :bad_gateway 503 = :service_unavailable 504 = :gateway_timeout 505 = :http_version_not_supported 507 = :insufficient_storage 510 = :not_extended
October 14, 2008
0 thanks

Wrapping peculiarities as of 2.x

In Rails 2.x word_wrap has been improved so that it no longer consumes multiple line-breaks or leading & trailing line-breaks.

word_wrap("\nOnce upon a time\n\nThe End\n") # => \nOnce upon a time\n\nThe End 

However it still doesn’t break long words

"supercalifragilisticexpialidocious".length # => 30 word_wrap("\nOnce upon a supercalifragilisticexpialidocious time", 15) # => \nOnce upon a\nsupercalifragilisticexpialidocious\ntime
October 14, 2008 - (v1.0.0 - v1.2.6)
1 thank

Wrapping peculiarities

word_wrap will consume multiple line-breaks as well as leading & trailing line-breaks.

word_wrap("\nOnce upon a time\n\nThe End\n") # => Once upon a time\nThe End 

word_wrap will NOT break long words

"supercalifragilisticexpialidocious".length # => 34 word_wrap("\nOnce upon a supercalifragilisticexpialidocious time", 15) # => Once upon a\nsupercalifragilisticexpialidocious\ntime 

If you want a function that will break long words & maintain multiple line-breaks try this alternative. Note it does add a line break at the end of the output.

def breaking_wrap_wrap(txt, col = 80) txt.gsub(/(.{1,#{col}})( +|$\n?)|(.{1,#{col}})/, "\\1\\3\n") end breaking_wrap_wrap("\nOnce upon a supercalifragilisticexpialidocious time", 15) # => \nOnce upon a\nsupercalifragil\nisticexpialidoc\nious time\n 

Regex-based code from http://blog.macromates.com/2006/wrapping-text-with-regular-expressions/

October 11, 2008 - (<= v2.0.3)
1 thank

Assert tag children

Code

#<div id="example"> # <ul> # <li class="btn_1"><a href="#">link1</a></li> # <li class="btn_2"><a href="#">link2</a></li> # </ul> #</div> assert_tag :tag => 'div', :attributes => {:id => "example"}, :child => { :tag => 'ul', :child => { :tag => 'li', :attributes => {:class => 'btn_1'}, :child => { :tag => 'a', :attributes => {:href => '#'}, :content => 'link1' }, :sibling => { :tag => 'li', :attributes => {:class => 'btn_2'}, :child => { :tag => 'a', :attributes => {:href => '#'}, :content => /link/ } } } }
October 10, 2008
2 thanks

Make an action onchange

collection_select(nil, :provincia_id, @provincias, :id, :nombre, {:prompt => “Seleccione una provincia”}, {:onchange => “#{remote_function(:url => {:controller => ‘direccions’, :action => ”update_pueblos“}, :with => ”‘provincia_id=’+value“)}”})

October 10, 2008
8 thanks

Implemented in database adapters

These methods are not implemented in the abstract classes. Instead, all database adapters implement these separately, if the feature is supported.

October 10, 2008 - (v2.1.0)
1 thank

Not implented yet

According to this method’s source, change_column_default is not implemented as well as change_column

October 9, 2008 - (<= v2.1.0)
12 thanks

Rendering nothing

If your controller action does not explicitly call render, Rails will, by default, attempt to locate and render the template corresponding to the action. It’s not uncommon, for example with Ajax calls, to want to render nothing. This will circumvent the default rendering and prevent errors on missing templates. To render nothing simply do the following:

render :nothing => true

Its important to note that this isn’t the same as returning no HTTP response. In fact, this results in an HTTP response with a status code of 200 OK being sent back with a blank content body. Why does it matter? Well, you can still test your controller by asserting that a :success response was returned.

October 8, 2008
3 thanks

Seriously! Do not forget the brackets

thank you source jamesandre.ws

the form_for([:admin, @user]) must have the [] brackets to avoid errors like “Only get requests are allowed”

<% form_for([:admin, @user]) do |f| %> <%= render :partial => 'form' %> <%= submit_tag "Create" %> <% end %>
October 7, 2008 - (v2.0.3 - v2.1.0)
0 thanks

Validate Mixup

Looks like the docs from validate got mixed up here. Only the last example is actually relevant to validates_each.

October 7, 2008 - (v2.0.3 - v2.1.0)
4 thanks

More on deprecation

This is not deprecated. I think the docs are confused because the validate, validate_on_create, and validate_on_update methods are actually callbacks and not explicitly defined on their own. The correct usage is the same as in the docs above.

October 6, 2008 - (<= v2.1.0)
1 thank

Multiple select and observe form

To make an observe form send all of the values selected in a multiple select html list, ensure you have the square brackets set in the name for the select tag e.g: group[]. This makes it pass the selected options in the params hash as an array.

<% remote_form_for :model, :url => {:action => ‘list’}, :html =>{:id => ‘model_id’} do |form| %>

<%= select_tag(‘group[]’, options_for_select(Model.find(:all).collect{|v|v.property}), :multiple => true) %>

<% end %>

<%= observe_form( ‘model’, :frequency => 2, :url => {:action => ‘list’} ) %>

October 2, 2008
10 thanks

:prefix option

Be aware!

By default, if you do select_month(Date.today, :field_name => ‘start’) it will generate select tag with name “date[start]”. If you want it to be something other than date[], add :prefix option, like this:

select_month(Date.today, :field_name => 'start', :prefix => 'timer') 

This will render select tag with name “timer[start]”.

Taken from sources of name_and_id_from_options method.