57

As a companion to Hidden features of Ruby.

Try to keep it to Rails since the other is a better place for Ruby-specific examples. One per post please.

Community
  • 1
  • 1
Brian
  • 4,931
  • 3
  • 32
  • 55
  • How can there be an answer to this question? And I see you have marked one already. – Chirantan Dec 11 '09 at 13:04
  • That's true. I just picked one since it was complaining at me about starting a bounty. But you're right. I took it off. – Brian Dec 11 '09 at 16:42
  • Why didn't this question took up like e.g. http://stackoverflow.com/questions/550632/favorite-django-tips-features ? Few votes, less answers ... – mark Sep 26 '10 at 01:08

15 Answers15

69

To avoid duplicate form submissions, Rails has a nice option for submit tags:

submit_tag "Submit", :disable_with => "Saving..."

This adds behavior to the submit button to disable it once clicked, and to display "Saving..." instead of "Submit".

Rails 4+

 DEPRECATION WARNING: :disable_with option is deprecated and 
 will be removed from Rails 4.1. Use 'data: { disable_with: 'Text' }' instead.

Thus the above becomes:

submit_tag 'Submit', data: { disable_with: 'Text' }
user664833
  • 18,397
  • 19
  • 91
  • 140
Jo Hund
  • 553
  • 5
  • 10
  • 1
    One of my favourites, though I've found that it breaks some javascript validators somehow. – Matt Grande Aug 05 '09 at 20:17
  • if you are using ajax for the submission, does it re-enable it? – raidfive Sep 26 '10 at 05:15
  • If you're using the simple_form gem, I found [this tip](http://stackoverflow.com/a/11610795/418602) helpful for applying `disable_with` feature across the board. – spume Jan 20 '14 at 15:55
22

integer.ordinalize is one little method that I just stumbled upon not to long ago.

1.ordinalize = "1st"
3.ordinalize = "3rd"
Dan Frade
  • 1,001
  • 9
  • 13
  • Edge Rails (4.0.beta) has a related method 'ordinal' which will return only the suffix. 1.ordinal returns 'st', 34.ordinal returns 'th' and so on. – Vijay Dev Feb 25 '12 at 17:10
21

I'm currently in love with div_for and content_tag_for

<% div_for(@comment) do %>
  <!-- code to display your comment -->
<% end %>

The above code renders this:

<div id="comment_123" class="comment">
  <!-- code to display your comment -->
</div>

Want the CSS class to be comment other_class? No problem:

<% div_for(@comment, :class => 'other_class') do %>
  <!-- code to display your comment -->
<% end %>

Want a span and not a div? No problem, content_tag_for to the rescue!

<% content_tag_for(:span, @comment) do %>
<% end %>

# Becomes...

<span id="comment_123" class="comment">
  <!-- code to display your comment -->
</span>

content_tag_for is also great if you want to prefix you id. I use it for loading gifs.

<% content_tag_for(:span, @comment, 'loading') do %>
  <%= image_tag 'loading.gif' -%>
<% end %>

# Becomes...

<span id="loading_comment_123" class="comment">
  <img src="loading.gif" />
</span>
rejin
  • 179
  • 1
  • 13
Matt Grande
  • 11,964
  • 6
  • 62
  • 89
18

To see a list of gems that are installed, you can run:

gem server

Then point your browser at:

http://localhost:8808

You get a nicely formatted list of your gems with links to rdoc, the web and any dependencies. Much nicer than:

gem list
Brian
  • 4,931
  • 3
  • 32
  • 55
16

You can take advantage of the fact that Ruby class definitions are active and that Rails caches classes in the production environment, to ensure that constant data is only fetched from the database when your application starts up.

For example, for a model that represents countries you'd define a constant that performs a Country.all query when the class is loaded:

class Country < ActiveRecord::Base
  COUNTRIES = self.all
  .
  .
  .
end

You can use this constant within a view template (perhaps within a select helper) by referring to Country::COUNTRIES. For example:

<%= select_tag(:country, options_for_select(Country::COUNTRIES)) %>
John Topley
  • 113,588
  • 46
  • 195
  • 237
13

in your environment.rb, you can define new date/time formats e.g.

[Time::DATE_FORMATS, Date::DATE_FORMATS].each do |obj|
  obj[:dots] = "%m.%d.%y"
end

so then in your views you can use:

Created: <%= @my_object.created_at.to_s(:dots) %>

which will print like:

Created: 06.21.09
jemminger
  • 5,133
  • 4
  • 26
  • 47
12

If you have a model with some class methods and some named scopes:

class Animal < ActiveRecord::Base
  named_scope 'nocturnal', :conditions => {'nocturnal' => true}
  named_scope 'carnivorous', :conditions => {'vegetarian' => true}

  def self.feed_all_with(food)
    self.all.each do |animal|
      animal.feed_with(food)
    end
  end
end

Then you can call the class methods through the named scope:

if night_time?
  Animal.nocturnal.carnivorous.feed_all_with(bacon)
end
tomafro
  • 5,788
  • 3
  • 26
  • 22
8

Rails 2.3.x now allows you to do:

render @items

much simpler..

John Topley
  • 113,588
  • 46
  • 195
  • 237
Ric8ard
  • 136
  • 4
  • nice one! we haven't been playing with 2.3 much - we're waiting for 3.0 at railsconf – Brian Apr 02 '09 at 13:45
  • To clarify: That will render a partial named 'items'? – Matt Grande Apr 02 '09 at 13:54
  • @Matt, yes - I was following on from the previous example, which used a collection named @items. Obviously, the view needs to be correctly named for this magic to work. – Ric8ard Apr 03 '09 at 12:16
  • 1
    With this syntax, doesn't rails look for the partial with the singularized name? e.g. "_item.html.erb" – Scott May 20 '09 at 18:26
7

I'll start with one of my favorites. When calling a partial with a collection, instead of looping through your collection and calling it for each item, you can use this:

render :partial => 'items', :collection => @items

This will call the partial once per item, and pass a local variable item each time. You don't have to worry about nil checking @items either.

Brian
  • 4,931
  • 3
  • 32
  • 55
  • For above example, you have to partial named as model name of collection object. If you have partial with different name for example `foo` you can then use `render :partial => 'foo', :collection => @items, as: :item`. Now you get object named `item` with in `foo` partial. – Engr. Hasanuzzaman Sumon Dec 17 '15 at 03:14
5

You can change the behaviour of a model for your test suite. Say you have some after_save method defined and you do not want it to happen in your unit tests. This is how it works:

# models/person.rb
class Person < ActiveRecord::Base

  def after_save
    # do something useful
  end

end


# test/unit/person_test.rb
require 'test_helper'

class PersonTest < ActiveSupport::TestCase

  class ::Person
    def after_save
      # do nothing
    end
  end

  test "something interesting" do
    # ...
  end
end
ericteubert
  • 4,531
  • 3
  • 31
  • 35
5

Funny feature is that array has special method for accessing its 42 element

a = []
a.forty_two

http://railsapi.com/doc/rails-v2.3.8/classes/ActiveSupport/CoreExtensions/Array/Access.html#M003045

Fivell
  • 11,829
  • 3
  • 61
  • 99
4

If you add routing for a resource:

ActionController::Routing::Routes.draw do |map|
  map.resources :maps
end

And register additional mime-types:

Mime::Type.register 'application/vnd.google-earth.kml+xml', :kml

You don't need a respond_to block in your controller to serve these additional types. Instead, just create views for the specific types, for example 'show.kml.builder' or 'index.kml.erb'. Rails will render these type-specific templates when requests for '/maps.kml' or '/maps/1.kml' are received, setting the response type appropriately.

tomafro
  • 5,788
  • 3
  • 26
  • 22
1

Get everything printed with rake routes programmatically:

Rails.application.routes
nurettin
  • 11,090
  • 5
  • 65
  • 85
1
ActionView::Base.default_form_builder = MyFormBuilderClass

Very useful when you're creating your own form builders. A much better alternative to manually passing :builder, either in your views or in your own custom_form_for helper.

August Lilleaas
  • 54,010
  • 13
  • 102
  • 111
1

The returning block is a great way to return values:

def returns_a_hash(id)
  returning Hash.new do |result|
   result["id"] = id
  end
end

Will return a hash. You can substitute any other types as well.

Brian
  • 4,931
  • 3
  • 32
  • 55