Flowdock

Notes posted to Ruby on Rails

RSS feed
December 10, 2010 - (>= v3.0.0)
3 thanks

complex conditions

If you need add complex conditions you can use this:

Model.where(:foo => 'bar').where(:attr => 1).update_all("author = 'David'")
December 9, 2010 - (<= v2.3.8)
0 thanks

Gotcha: index name must be a string, not a symbol

Using rails 2.3.8 I kept getting an exception when i tried:

add_index :widgets, [:colour, :weight], :name => :index_by_colour_weight

it’s solved by using:

add_index :widgets, [:colour, :weight], :name => 'index_by_colour_weight'
December 8, 2010 - (>= v3.0.0)
3 thanks

helpers using options for select

You can now add html options to select options by creating a container with items like the following:

Code Example

['display','value',:class => 'option_class']

This will produce:

Code Example

<option value="value" class="option_class">display</option>
December 8, 2010
0 thanks

typo

ActionController::Steaming => ActionController::Streaming

December 2, 2010 - (<= v3.0.0)
1 thank

Checks if attribute is equal to '1' by default

It’s easy to overlook the :accept option which dictates that the attribute shall be ‘1’, not ‘yes’, not true, but ‘1’ only for validation to pass.

For ‘1’ shall the value be, no more, no less. ‘1’ shall be the value thou shalt validate, and thy validation shall check for ‘1’. ‘2’ shalt not thou validate, neither ‘3’, nor ‘0’, excepting that thou shall then set the value to ‘1’. true is right out. Once the value ‘1’, being the value of the attribute named, then thou shall have validation and thy object shall be valid.

November 22, 2010
0 thanks

another way

because you can pass inline procs as well:

before_filter {authorize(args)}
November 18, 2010
0 thanks

word_wrap with breaking long words

Code

def breaking_word_wrap(text, *args)
   options = args.extract_options!
   unless args.blank?
     options[:line_width] = args[0] || 80
   end
   options.reverse_merge!(:line_width => 80)
   text = text.split(" ").collect do |word|
     word.length > options[:line_width] ? word.gsub(/(.{1,#{options[:line_width]}})/, "\\1 ") : word
   end * " "
   text.split("\n").collect do |line|
     line.length > options[:line_width] ? line.gsub(/(.{1,#{options[:line_width]}})(\s+|$)/, "\\1\n").strip : line
   end * "\n"
end

breaking_word_wrap("Once upon a supercalifragilisticexpialidocious time",15)
# => Once upon a\nsupercalifragil\nisticexpialidoc\nious  time
November 14, 2010 - (v3.0.0)
2 thanks

Documentation (v3.0.1)

Documentation for this module (taken from ActiveSupport 3.0.1):

# A typical module looks like this
#
#   module M
#     def self.included(base)
#       base.send(:extend, ClassMethods)
#       base.send(:include, InstanceMethods)
#       scope :foo, :conditions => { :created_at => nil }
#     end
#
#     module ClassMethods
#       def cm; puts 'I am a class method'; end
#     end
#
#     module InstanceMethods
#       def im; puts 'I am an instance method'; end
#     end
#   end
#
# By using <tt>ActiveSupport::Concern</tt> the above module could instead be written as:
#
#   module M
#     extend ActiveSupport::Concern
#
#     included do
#       scope :foo, :conditions => { :created_at => nil }
#     end
#
#     module ClassMethods
#       def cm; puts 'I am a class method'; end
#     end
#
#     module InstanceMethods
#       def im; puts 'I am an instance method'; end
#     end
#   end
November 14, 2010 - (v1.0.0 - v2.3.8)
0 thanks

In Rails 3 you can find it here

In Rails 3 - this validation is moved to the HelperMethods

November 12, 2010
1 thank

nested attribute gotcha

Just adding to what @diabolist said :

class House

has_many :doors
accepts_nested_attributes_for :doors

attr_accesible :address, :doors_attributes
# NOTE its plural

end

November 9, 2010
0 thanks

How to perform :onchange ajax call using jQuery (Rails 3)

As remote_function no longer exists in Rails 3, here is some handy substitution

<%= select_tag :assignee_id, options_for_select([["A",1],["B",2]]), 
                                :onchange => "$.post('#{model_singular_path(id)}', {'_method':'put', 'model_name[model_field]':this.value} );" %>

You can obviously pass more attributes, change method etc.

November 3, 2010
1 thank

correction

I think what metavida meant was

User.find(1, 3) # ActiveRecord::RecordNotFound error

not

User.find_by_id(1, 3) # this will just return user 1
November 3, 2010
0 thanks

RecordNotFound when any id not found

As an example of bansalakhil’s explanation.

User.find_by_id(1) #=> #<User:0x3d54a3c @attributes={"id"=>1}>
User.find_by_id(2) #=> #<User:0x3d519a4 @attributes={"id"=>2}>
User.find_by_id(3) #=> nil
User.find_by_id(1, 2) #=> an Array with 2 User instances
User.find_by_id(1, 3) #=> an ActiveRecord::RecordNotFound error
November 3, 2010 - (v2.3.2 - v2.3.8)
0 thanks

Get the primary schema's name

If you’re using PostgreSQL and you’ve changed schema, sometimes you need to know what schema you’re in.

ActiveRecord::Base.connection.schema_search_path.split(",").first
October 31, 2010
1 thank

A named_scope also responds to model class methods

for instance

class Student < ActiveRecord::Base

   named_scope :sophomore, :conditions => 'year=2'

   def self.eligible_to_vote
     select{|s| s.age >= 18}
   end

end

ss = Student.sophomore.eligible_to_vote
October 27, 2010
0 thanks

Pluralize Without Count (inline version)

= pluralize(item.categories.count, ‘Category’).sub(/d+s/, ”)

October 26, 2010
3 thanks

Polymorphic has_many within inherited class gotcha

Given I have following classes

class User < ActiveRecord::Base
end

class ::User::Agent < ::User
 has_many :leads,  :as => :creator
end

I would expect, that running

User::Agent.first.leads

will result in following query

SELECT "leads".* FROM "leads" WHERE ("leads".creator_id = 6 AND "leads".creator_type = 'User::Agent')

however it results in

SELECT "leads".* FROM "leads" WHERE ("leads".creator_id = 6 AND "leads".creator_type = 'User')

Possible solutions:

  • Make User class use STI - polymorphic relations will then retrieve correct class from :type field (however in my situation it was not an option)

  • If You do never instantiate User class itself, mark it as abstract

class User < ActiveRecord::Base
 self.abstract_class = true
end
  • If You do instantiate User class, as last resort You can overwrite base_class for User::Agent

class ::User::Agent < ::User
 has_many :leads,  :as => :creator

 def self.base_class
  self
 end
end
  • If none of above is an option and You do not care that You will lose some of relation’s features, You can always

class User::Agent < ::User
 has_many :leads,
          :as => :creator,
          :finder_sql => %q(SELECT "leads".* FROM "leads" WHERE ("leads".creator_id = #{id} AND "leads".creator_type = 'User::Agent'))
end
October 26, 2010 - (>= v3.0.0)
0 thanks

Use super to override, and not alias_method_chain

Somehow, If you want to extend the behaviour of attributes=,

alias_method_chain does not work. It simply breaks (could not find out how exactly).

def attributes_with_some_feature=(new_attributes, guard_protected_attributes = true)
  attributes_without_some_feature=(new_attributes, guard_protected_attributes)
end
alias_method_chain :attributes=, :some_feature

this breaks the code. dynamic finders and assignments didn’t work as before (Even though no behaviour has changed yet).

Instead,

def attributes=(new_attributes, guard_protected_attributes = true)
  # custom code
  super(new_attributes, guard_protected_attributes)
end

does work as expected.

I prefer using alias_method_chain for breaking open existing functionality, but in this case it won’t work.

October 26, 2010
1 thank

null to no effects

change_column will not query to replace the null values when you change null to false, even if you have a default set. This may cause the query to fail (may depend on the database used).

change_column_null will optionally take a value to replace nulls if you are setting null to false. If you want to set a default and disallow nulls you likely can’t do both in one change_column call.

October 22, 2010
1 thank

doesn't work directly off a class.

for some reason this method only works on relation objects, not directly on an AR class.

# doesn't work
User.offset(3).limit(1)

# does work
User.limit(1).offset(3)

there’s an closed ticket for this here http://rails.lighthouseapp.com/projects/8994/tickets/5688-modeloffsetxlimitx-unknown-offset-method-exception and should be resolved in the next release of rails.

October 22, 2010
1 thank

still broken

add_index is a different method. I think this is just a bug and it’s broken.

October 21, 2010 - (v3.0.0)
0 thanks

Validate number

option like :greater_than still supported

use like this

Code example

validates :position, :presence => true, :numericality => {:greater_than => 0}

October 20, 2010
6 thanks

use raw() instead

Don’t use this method unless you’re sure your string isn’t nil. Instead use the raw() method, which wont raise an exception on nil.

October 19, 2010
1 thank

Looking for the docs?

Check the ClassMethods – the docs on filters are there.

October 16, 2010 - (>= v3.0.0)
10 thanks

needs to be paired with respond_to

Needs to be paired with respond_to at the top of your class.

class MyController < ApplicationController
  respond_to :js, :html
October 13, 2010
11 thanks

Sending array parameters

Another technique to use when you need to send an array parameter is pass in the :multiple option.

check_box("puppy", "commands", {:multiple => true}, "sit", nil)
check_box("puppy", "commands", {:multiple => true}, "fetch", nil)
check_box("puppy", "commands", {:multiple => true}, "roll_over", nil)

If all checkboxes are checked, the paramters will be:

"puppy" => {"commands" => ["sit", "fetch", "roll_over"]}

NOTE: because of the gotcha, the hidden fields will be inserted and any unchecked boxes will be sent as “” (empty string). You will need to filter those values out in your model:

class Dog < ActiveRecord::Base
  def commands=(commands)
    commands.reject(&:blank?)
  end
end
October 13, 2010 - (v2.1.0 - v3.0.0)
1 thank
October 11, 2010 - (>= v3.0.0)
0 thanks