Flowdock

Notes posted to Ruby on Rails

RSS feed
October 15, 2009
4 thanks

Have check_box checked by default

In addition to comment below, you can make a column with default value so in your forms it will be enabled by default and behave correctly with validation errors unlike :checked => true

in your migration

add_column :accounts, :ssl_enabled, :boolean, :default => 1
October 15, 2009
2 thanks
October 14, 2009
2 thanks

build_association deletes existing dependent record

Surprisingly (at least I was surprised), when an associated record exists, the build_association method immediately NULLs the foreign key in the database.

So if you write a singleton “new” action for the association in the obvious way (calling build_association), then just visiting the page will disconnect an existing associated record. This violates the principle that a GET request shouldn’t affect the database.

To avoid this, you can check for an existing association first, and redirect to the show action.

October 12, 2009
0 thanks

Use it to solve FixtureClassNotFound errors.

If you are using a non standard table name by means of set_table_name in your model:

class MyClassName < ActiveRecord::Base
  set_table_name "mytablename"
end

then you will get FixtureClassNotFound errors when you try to use fixtures in you unit tests. To solve this use set_fixture_class inside your test:

require 'test_helper'
class MyClassNameTest < ActiveSupport::TestCase
  set_fixture_class :mytablename => MyClassName  
end

and rename your fixture file to mytablename.yml

October 7, 2009 - (>= v2.3.2)
3 thanks

Streaming XML with Builder

To generate larger XMLs, it’s a good idea to a) stream the XML and b) use Active Record batch finders.

Here’s one way of doing it:

def my_action
  @items = Enumerable::Enumerator.new(
    Item.some_named_scope,
    :find_each,
    :batch_size => 500)

  respond_to do |format|
    format.xml do
      render :text => lambda { |response, output|
        extend ApplicationHelper

        xml = Builder::XmlMarkup.new(
          :target => StreamingOutputWrapper.new(output),
          :indent => 2)
        eval(default_template.source, binding, default_template.path)
      }
    end
  end
end

The Builder template does not need to be modified.

October 5, 2009
2 thanks

Use camelize with singular words

To make the business example work, use camelize instead of classify:

"business".camelize     # => "Business"
October 3, 2009
0 thanks

sort_by

array.sort_by {|element| [element.foo, element.bar.name, element.baz]}

Taken from http://redcorundum.blogspot.com/2006/10/using-sortby-instead-of-sort.html

October 2, 2009
2 thanks

Making ActiveRecord models readonly

To force an ActiveRecord model to be read only you can do something along these lines:

class DelicateInfo < ActiveRecord::Base

 def readonly?
  true
 end

end

When you try to save the model it will raise an ActiveRecord::ReadOnlyRecord exception:

info = DelicateInfo.first
info.save # => ActiveRecord::ReadOnlyRecord

Note, however, that destroy and delete will still work on the model unless you intercept those calls

October 2, 2009
4 thanks

form_tag with named route and html class

<% form_tag position_user_card_path(@user, card), :method => :put, :class => ‘position-form’ do %>

October 1, 2009
0 thanks

This code prevent's frome redirect_to(:back) looping

Prevent redirect_to(:back) looop

begin

# loop check
if session[:last_back] != request.env['HTTP_REFERER']
  redirect_to(:back)
  session[:last_back] = request.env['HTTP_REFERER']
else
  # raise on error
  raise ActionController::RedirectBackError
end

rescue ActionController::RedirectBackError

# fallback on loop or other :back error
redirect_to(:action => :index)

end

October 1, 2009
0 thanks

ActiveResource validation is a little different

Given the following model on the remote end:

class Person < ActiveRecord::Base
 validates_presence_of :first_name, :last_name, :email
end

And this ActiveResource on the client end:

class Person < ActiveResource::Base
 self.site = "http://api.people.com:3000/" 
end

Validation messages will only be returned after an attempted save call on the client end - eg:

person = Person.new( :first_name => 'Billy', :emails => "william@anotherplanet.co.za" )
person.valid?                 # => true
person.errors.full_messages   # => []
person.save                   # => false
person.valid?                 # => false
person.errors.full_messages   # => ["Last name can't be empty"]

In ActiveResource::Base it is suggested that you can perform client site validation with something like this:

class Person < ActiveResource::Base
 self.site = "http://api.people.com:3000/"
 protected
  def validate
   errors.add("last name", "can't be empty") if last_name.blank?
  end
end
October 1, 2009
0 thanks

Update attributes on mulitple models

Updates attributes on multiple models, saves each if validations pass.

def update_multiple

  @items = Item.find(params[:item_ids])
  @items.each do |item|
    item.attributes = params[:item].reject { |k,v| v.blank? }
  end
  if @items.all?(&:valid?)
    @items.each(&:save!)
    flash[:notice] = "Updated items!"
    redirect_to items_path
  else
    flash[:notice] = "Please enter valid data."
    render :action => 'edit_multiple'
  end
end
September 30, 2009
2 thanks

See also: ActiveRecord::Base#increment

This is a class-level method. For the instance-level equivalent see: ActiveRecord::Base#increment

item = Item.find(1)
item.foo_count # => 0
Item.increment_counter(:foo_count, 1)
item.foo_count # => 0
item.reload
item.foo_count # => 1
item.increment(:foo_count)
item.foo_count # => 2
September 29, 2009
1 thank

Passing parameters to before_filter

I’ve found on the net 2 ways to pass parameters to before_filter:

method 1:

before_filter do |c|
c.class.module_eval do
private
def custom_filter
authorize(args)
end
end
end
before_filter :custom_filter

method 2:

before_filter do |c|
c.send(:authorize, args)
end
September 24, 2009 - (>= v2.2.1)
0 thanks
September 24, 2009 - (>= v2.2.1)
0 thanks
September 24, 2009 - (>= v2.2.1)
0 thanks
September 24, 2009 - (>= v2.2.1)
0 thanks
September 24, 2009 - (>= v2.2.1)
0 thanks
September 24, 2009 - (>= v2.2.1)
0 thanks
September 24, 2009 - (>= v2.2.1)
0 thanks
September 24, 2009 - (>= v2.2.1)
0 thanks
September 24, 2009 - (>= v2.2.1)
0 thanks
September 24, 2009 - (>= v2.2.1)
0 thanks
September 24, 2009 - (>= v2.2.1)
2 thanks
September 24, 2009 - (>= v2.2.1)
0 thanks
September 24, 2009 - (>= v2.2.1)
0 thanks
September 18, 2009 - (>= v2.3.2)
0 thanks

Regenerate the JavaScript after each RJS call

RISCfuture - I had trouble using sortable_element_js in my rjs (javascript error when I used options), but had success with page.sortable(‘the_id’,{a_hash_of_my_options}) in my rjs

September 14, 2009
6 thanks

Pluralize Without Count

Helper method that returns the word without the count.

application_helper.rb

def pluralize_without_count(count, noun, text = nil)
  if count != 0
    count == 1 ? "#{noun}#{text}" : "#{noun.pluralize}#{text}"
  end
end

Example usage:

_form.html.erb

<%= pluralize_without_count(item.categories.count, 'Category', ':') %>