Notes posted by THAiSi
RSS feedYou 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
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
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
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.
Use ModelClass.model_name.human
eg. Person.model_name.human will return the i18n name for the model.
see for more info: ActiveModel::Translation
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
Requirements for extra parameters not working
nm. just delete this entry
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)
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
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.
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.
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?