Notes posted by THAiSi

RSS feed
May 16, 2014
0 thanks

You can add if: :query_method and unless: :query_method

You can make the callback conditional:

before_save :before_method, if: :needs_before_method?

private

def needs_before_method?
   false
end

def before_method
  # .. 
end
August 5, 2011
0 thanks

Speccing read_only requirements

To test if an attribute is defined readonly:

class MyModel < ActiveRecord::Base
  attr_readonly :important_type_thingie
end

#RSpec
describe MyModel do
 its('class.readonly_attributes') { should include "important_type_thingie" }

 it "should not update the thingie" do
   m = create :my_model, :important_type_thingie => 'foo'
   m.update_attributes :important_type_thingie => 'bar'
   m.reload.important_type_thingie.should eql 'foo'
 end
end
January 26, 2011 - (>= v3.0.0)
2 thanks

Use this for validatating nested forms

When you create a nested form, and want the main object to validate all nested models, you should make all the nested models dirty or validations will not run upon them.

class Order < ActiveRecord::Base
  has_many :order_lines
  accepts_nested_attributes_for :order_lines

  before_validation :mark_order_lines_as_changed

  private
  def mark_order_lines_as_changed
    order_lines.each(&:updated_at_will_change!)
  end
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 11, 2010 - (>= v3.0.0)
0 thanks
October 11, 2010 - (>= v3.0.0)
1 thank

Use ModelClass.model_name.human

eg. Person.model_name.human will return the i18n name for the model.

see for more info: ActiveModel::Translation

August 21, 2009
2 thanks

Passing parameters to custom formbuilders

If you implement your own formbuilder, the options passed are available as @options inside your formbuilder. If you want those configuration options passed to all builders in the fields_for sections, use the following code in your form builder:

def fields_for_with_options(record_or_name_or_array, *args, &block) options = args.extract_options! fields_for_without_options(record_or_name_or_array, *(args << options.merge(@options)), &block) end alias_method_chain :fields_for, :options

Usage:

form_for @my_object, :builder => MyCustomFormbuilder, :some_setting => :cool
June 13, 2009
0 thanks
June 2, 2009 - (>= v2.2.1)
1 thank

Do not create an [ ] method

I created a helper method to access some meta data using

def [](name)
  # do stuff
end

This breaks ActiveRecord behaviors. all belongs_to relations were broken

eg.

class Image
  belongs_to :album
end

i = Image.find :first
i.album_id # 1
i.album # nil

Album.find 1 # works

If you experience this behavior, you probably created a method that breaks the default systematics (like I did with the [ ] method)

April 27, 2009
0 thanks

has_one through belongs_to not working

code example:

class Company < ActiveRecord::Base
  has_many :route_lists
end

class RouteList < ActiveRecord::Base
  belongs_to :company
  has_many :routes
end

class Route < ActiveRecord::Base
  belongs_to :route_list
  has_one :company :through => :route_list
end

This creates an invalid SQL query, where the keys in the join between route and routelist are switched, when used as an include:

Routes.find :all, :conditions => ["companies.type = ?", "Account"], :include => :company

route_lists.route_list_id = route.id

instead of: route_lists.id = route.route_list_id

March 12, 2009
12 thanks

User a block to extend your associations

You can use blocks to extend your associations with extra methods.

code sample

has_many :children, :dependent => :destroy do
  def at(time)
    proxy_owner.children.find_with_deleted :all, :conditions => [
      "created_at <= :time AND (deleted_at > :time OR deleted_at IS NULL)", { :time => time }
    ]        
  end      
end

Model.children.each # do stuff
Model.children.at( 1.week.ago ).each # do old stuff

you must use ‘proxy_owner’ to link back to your model.

March 11, 2009
2 thanks

Use table_exists? in initializers

When using ActiveRecords in initializers, eg. for creating small constant data on startup, use table_exists? for those statements.

the initalizers are also called for migrations, etc, and if you are installing a new instance of the project these initializers will fail the migration to create those tables in the first place.

February 27, 2009 - (v1.2.6 - v2.2.1)
0 thanks

read_attribute?

The source if this method and other methods indicate the reading of read_attribute (protected)

there is no documentation about the insides of this method, the only entry listed is read_attribute (private) which is deprecated since 1.2.6?