Hidden Features of Ruby on Rails
Ruby on-RailsRuby on-Rails Problem Overview
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.
Ruby on-Rails Solutions
Solution 1 - Ruby on-Rails
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' }
Solution 2 - Ruby on-Rails
integer.ordinalize is one little method that I just stumbled upon not to long ago.
1.ordinalize = "1st"
3.ordinalize = "3rd"
Solution 3 - Ruby on-Rails
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>
Solution 4 - Ruby on-Rails
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
Solution 5 - Ruby on-Rails
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)) %>
Solution 6 - Ruby on-Rails
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
Solution 7 - Ruby on-Rails
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
Solution 8 - Ruby on-Rails
Rails 2.3.x now allows you to do:
render @items
much simpler..
Solution 9 - Ruby on-Rails
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.
Solution 10 - Ruby on-Rails
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
Solution 11 - Ruby on-Rails
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
Solution 12 - Ruby on-Rails
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.
Solution 13 - Ruby on-Rails
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.
Solution 14 - Ruby on-Rails
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.
Solution 15 - Ruby on-Rails
Get everything printed with rake routes programmatically:
Rails.application.routes