Flowdock

Recent notes

RSS feed
January 3, 2011
1 thank

Rollback

To rollback the transaction

transaction do
  unless user.save && company.save
     raise raise ActiveRecord::Rollback
  end
end

Or - catch anonymous exceptions, roll back and re-throw error

transaction do
  user.save
  company.save
  x = 1/0
rescue
  exp = $!
  begin
    raise ActiveRecord::Rollback
  rescue
  end
  raise exp
end
January 1, 2011
0 thanks

read_attribute/write_attribute

I went back and looked at my notes from my previous project.

Yep, these methods were removed from ActiveRecord::Base in an early version, and moved into a Module called AttributeMethods, which is then included in ActiveRecord::Base.

So the methods are available in ActiveRecord::Base… but they are defined elsewhere.

APIdock could benefit from some better linkage, and possibly a better parser to get some of the more dynamically defined methods.

January 1, 2011
0 thanks

Missing method definitions

THAiSi, and any others wondering this as well:

I’ve done some pretty extensive digging in to the rails code, for a couple of projects, and I’ve found that there are several methods that don’t appear in APIDock. There are several reasons for this, but I’m not sure read_attribute falls under any of them. Perhaps it has something to do with read_attribute being defined and/or redefined in the foundation for rails (they actually do some stuff to mask out a ton of default behavior of ruby for these classes, and add their own level of inheritance functionality. Things like cattr_accessor - which is like attr_accessor, but for a class, rather than an object…

class Object < ActiveRecord::Base
  cattr_accessor some_attr
end

would allow for reading and writing a value on the class, itself. i.e.

Object.some_attr = 5

In addition, several methods, regarding validations, callbacks, etc. are actually defined dynamically, based on things like the model name, using class_eval. These are not grabbed *at all* by APIdock, and this is where I spent most of my effort in reverse engineering how rails behaves.

Hope that helps.

December 21, 2010 - (<= v2.3.8)
0 thanks

reload next time referenced

After calling reset on an association, it will be forced to be reloaded next time it’s referenced. Useful after you manipulate an associated object/collection with SQL, and you want to make sure subsequent uses don’t get the invalid cached version. Better than reload in that it doesn’t actually reload if not needed.

December 20, 2010
0 thanks

New Website for RedCloth

The Link above doesnt work anymore. This one should be the new one: http://redcloth.org/

December 16, 2010 - (>= v2.0.0)
0 thanks

RE: Alternative hostname generation method

According to compute_asset_host as of rails 2.0.0 the %d expansion works in the same way, it’s not a random number generated on each call but the source hash mod 4.

In my brief testing in rails 2.3.9, %d doesn’t appear to work if you use a Proc, so manual generation is of use in that case.

December 11, 2010 - (v3.0.0)
2 thanks

I18n file to change an attribute's name

If you are using Active Record, use a locale file like the one below to change a model’s attribute’s human name.

en:
  activerecord:
    attributes:
      picture:
        explanation: Description

Without using the locale file:

ruby-1.9.2-p0 > Picture.human_attribute_name("explanation")
 => "Explanation" 

Using the locale file:

ruby-1.9.2-p0 > Picture.human_attribute_name("explanation")
 => "Description" 
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 24, 2010
0 thanks

Includes the dot

Returns the extension including the ‘.’.

E.g.

Pathname("/path/to/file.rb").extname
#=> ".rb"
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 9, 2010
8 thanks

NOT Equivalent to Array#reject!

@tadman is wrong. There is a difference and, trust me, it can bite:

1.9.2 > [1,2,3,4].delete_if {|x| x > 10}
 => [1, 2, 3, 4] 
1.9.2 > [1,2,3,4].reject! {|x| x > 10}
 => nil 

That is, if reject! hasn’t rejected anything, it returns nil.

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 28, 2010
0 thanks

map_with_index

Of course such a method does not exist, however we can simulate it easily

%w(a b c).to_enum(:each_with_index).map{|a,i| "#{a}, #{i}"}
=> ["a, 0", "b, 1", "c, 2"]
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