Notes posted to Ruby on Rails

RSS feed
April 26, 2012
5 thanks
April 25, 2012 - (>= v3.1.0)
6 thanks

HTML5 data- attributes using RESTful approach

HTML5 specifies extensible attributes like data-foo=“bar” (or as in Twitter Bootstrap data-toggle=“modal”), which poses two problems for Rails.

First, if you’re using symbol notation in link_to to specify attributes, this fails (dash is not a valid symbol character), so

Invalid!

link_to "Edit", @user, :class => "btn", :data-toggle => "modal"

There are two solutions:

  1. put the symbols in quotes,

  2. use the special :data hash

Solution 1: Quote Symbols

link_to "Edit", @user, :class => "btn", "data-toggle" => "modal"

Solution 2: Use the :data hash

link_to "Edit", @user, :class => "btn", :data => {:toggle => "modal"}

Resulting HTML

<a href="/users/1" class="btn", data-toggle="modal">Edit</a>

The second is minimally documented, but as a hash, can accept multiple values and is perhaps a little cleaner

April 22, 2012
0 thanks

I got it

Perfect match to work with attr_accessible

April 19, 2012 - (<= v3.2.1)
0 thanks

Locale

To change default locale by the parameter you can set :locale option, like below:

select_date 'user', 'birth', :locale => 'de'
April 19, 2012 - (v3.1.0 - v3.2.1)
0 thanks

Missed close tag

At the page http://apidock.com/rails/ActionView/Helpers/TagHelper/tag

<tt>.data()</tt> should be instead of <tt>.data()<tt>

April 3, 2012
1 thank

Looks like this method has trouble with attributes:

ex:

require 'rubygems'
require 'bundler'
require 'active_support/core_ext'
require 'pp'

xml  = 
  '<test id="appears">
    <comment id="doesnt appear">
      it worked
    </comment>
    <comment>
     see!
    </comment>
    <comment />
  </test>'

hash = Hash.from_xml(xml)

pp hash

#=>{"test"=>{"id"=>"appears", "comment"=>["it worked", "see!", nil]}}

# Notice how the id attribute on the first comment element doesn't appear.
April 2, 2012
1 thank

Options select_hour

In my view I wanted to do this <%= select_hour(@hour, :start => 8, :end => 12) %> but did not work. I looked at the documentation and have not seen anything like it. http://api.rubyonrails.org/classes/ActionView/Helpers/DateHelper.html#method-i-select_hour

So I studied how it worked this helper. http://api.rubyonrails.org/classes/ActionView/Helpers/DateHelper.html#method-i-select_hour develop and achieve this:

the helper application:

module DataAnnouncementsHelper

class HelperDate < ActionView::Helpers::DateTimeSelector
  def select_hour
    if @options[:use_hidden] || @options[:discard_hour]
      build_hidden(:hour, hour)
    else
      build_options_and_select(:hour, hour, :end => @options[:end], :start => @options[:start], :ampm => @options[:ampm])
    end
  end
end

def select_hour(datetime, options = {}, html_options = {})
   HelperData.new(datetime, options, html_options).select_hour
end

end

The view:

<%= select_hour(@hour, :start => 8, :end => 12) %>

Where @hour = 10 the result is:

<select id=“date_hour” name=“date[hour]”>

<option value="08">08</option>
<option value="09">09</option>
<option value="10" selected="selected">10</option>
<option value="11">11</option>
<option value="12">12</option>

</select>

March 29, 2012 - (<= v3.2.1)
1 thank

JQuery script for dynamically adding and removing fields_for

I like drogus idea. But I wanted a cleaner one, so I created an unobtrusive JQuery script to have the same functionality.

Example Usage:

<%= form_for @post do |form| %>
  Title: <%= form.text_field :title %>
  Body: <%= form.text_field :body %>

  Tags:
  <div id="tag-list"></div>

  <div class="numerous">
    <div class="numerous-form">
      <%= form.fields_for :tag, Tag.new, :child_index => "replace_this" do |f| %>
        <%= f.text_field :name %>
        <%= f.hidden_field :_destroy, :value => 0, :class => "numerous-remove-field" %>
        <%= link_to "delete", "#", :class => "numerous-remove" %>
      <% end %>
    </div>

    <%= link_to "add tag", "#", :class => "numerous-add", :id => "for-tag-list" %>
  </div>
<% end %>

See script at: http://github.com/kbparagua/numerous.js

March 28, 2012 - (>= v3.0.0)
0 thanks

:as option

Code

root :to => 'projects#index', :as => 'foobar'

will generate a helper

foobar_path
March 28, 2012
1 thank

Disable layout on ajax

In actions that may or may not be loaded via ajax I use:

render :layout => !request.xhr?

For an entire controller I might use something like:

layout :has_layout?

private
  def has_layout?
    request.xhr? ? false : controller_name
  end

What seems unusual is that

layout true

will try look for the layout true.erb

March 27, 2012 - (v3.1.0 - v3.2.1)
2 thanks
March 27, 2012 - (v3.1.0 - v3.2.1)
1 thank
March 27, 2012
5 thanks

Makes it possible to use a scope through an association

This is a very useful method if you want to to use a scope through an association:

class Book < ActiveRecord::Base
  scope :available, where(:available => true)
end

class Author < ActiveRecord::Base
  has_many :books
  scope :with_available_books, joins(:books).merge(Book.available)
end

# Return all authors with at least one available book:
Author.with_available_books

See http://asciicasts.com/episodes/215-advanced-queries-in-rails-3 for more info.

March 27, 2012
7 thanks

Reorder

If you want to override previously set order (even through default_scope), use reorder() instead.

E.g.

User.order('id ASC').reorder('name DESC')

would ignore ordering by id completely

March 27, 2012 - (>= v3.2.1)
0 thanks

Example to auto download

Controller

op = Operation.find(params[:id])
fname = "operation_#{op.id}_#{DateTime.now.to_i}.csv"
send_data op.export(params[:url_type]), 
  :type => 'text/csv; charset=iso-8859-1; header=present',
  :disposition => "attachment; filename=#{fname}.csv"

export_csv

def export(url_type)
  csv_data = CSV.generate do |csv|
    csv << self.header_columns # simple array ["id","name"]
    url_items = @operation.url_items.where(:url_type => url_type)
    url_items.each do |url_item|
      csv << self.process_row(url_item)  # simple array [1,"bob"]
    end 
  end 
  return csv_data
end
March 26, 2012 - (<= v3.1.0)
1 thank

Use exist scopes on default_scope - pay attention

To use exists scopes on default_scope , you can use something like:

class Article < ActiveRecord::Base
  scope :active, proc {
    where("expires_at IS NULL or expires_at > '#{Time.now}'")
  }

  scope :by_newest, order("created_at DESC")

  default_scope by_newest
end

But, if you would add a filter, and it require a lazy evaluate, use block on default_scope declaration, like:

default_scope { active.by_newest }
March 22, 2012 - (>= v3.1.0)
2 thanks

Deprecation in 3.1+

In Rails 3.1 and higher, just use ruby’s SecureRandom, e.g.

Before

ActiveSupport::SecureRandom.hex

After

SecureRandom.hex
March 15, 2012 - (>= v3.2.1)
1 thank

Deprecated proxy_owner

Just change your

proxy_owner

calls to

@association.owner

Found it here: http://mileszs.com/deprecation-warnings-for-proxyowner-in-rails

March 10, 2012
3 thanks

flash messages

In rails 3.1 the following does not work for me

redirect_to { :action=>'atom' }, :alert => "Something serious happened" 

Instead, you need to use the following syntax (wrap with parens)

redirect_to({ :action=>'atom' }, :alert => "Something serious happened")
March 5, 2012
0 thanks

Example of conditions using

f.e.

validates :number, :presence => { :if => :quota_file? }

def self.quota_file?
  quota_file?
end
March 5, 2012
0 thanks

won't refresh updated_at

This will not cause :updated_at column to refresh, while ActiveRecord::Base#increment! would.

February 20, 2012
0 thanks

How to user method 'from'

example

User.from('posts').to_sql
# => "SELECT `users`.* FROM posts"
February 20, 2012
0 thanks

How to user method from'

example

User.from('posts').to_sql
# => "SELECT `users`.* FROM posts"
February 15, 2012 - (<= v2.3.8)
0 thanks

@ssoroka and @drova and future readers

I guess these two have already found a solution, but future readers might have not. index and references do not map perfectly

change_table :foo do |t|
  t.references :bar
  t.index      :bar_id
end

references gets the model name while index gets the column name.

February 15, 2012 - (<= v2.3.8)
0 thanks

Not working in create_table

When using the index method within a create_table statement, it does not have any side effect - at least not in MySQL.

create_table :comment do |t|
  t.belongs_to :post

  t.timestamps

  # not working inside create_table !
  t.index :post_id
end

It is working properly in change_table though

change_table :comment do |t|
  t.belongs_to :user

  # this works inside change_table
  t.index :user_id
end

Unfortunately this flaw is not reported in any way. The index is just not created.

I have only tested this with the mysql2 driver in Rails 2.3.x. I’m not sure, if this happens in other versions/adapters as well.

February 10, 2012 - (>= v3.1.0)
0 thanks

:defaults no longer work

I’m afraid that :defaults option doesn’t work anymore.

<%= javascript_include_tag :defaults %>

it loads “defaults.js”

Instead, to load all .js files now use

<%= javascript_include_tag "application" %>
February 9, 2012 - (<= v3.1.0)
1 thank

:only, :except and passing in multiple parameters

To specify that the filter should be applied to or excluded from given controller actions, use the :only and :except parameters. To pass in multiple controller actions use an array:

after_filter :authorize, :except => [:index, :show]
after_filter :authorize, :only => :delete

Stolen from: http://apidock.com/rails/ActionController/Filters/ClassMethods/before_filter