Is Alias_Method_Chain Synonymous with Alias_Method

Is alias_method_chain synonymous with alias_method?

No. alias_method is a standard method from Ruby. alias_method_chain is a Rails add-on designed to simplify the common action of aliasing the old method to a new name and then aliasing a new method to the original name. So, if for example you are creating a new version of the method method with the new feature new_feature, the following two code examples are equivalent:

alias_method :method_without_new_feature, :method
alias_method :method, :method_with_new_feature

and

alias_method_chain :method, :new_feature

EDIT

Here is a hypothetical example: suppose we had a Person class with a method rename. All it does is take a string like "John Doe", split on the space, and assign parts to first_name and last_name. For example:

person.rename("Steve Jones")
person.first_name #=> Steve
person.last_name #=> Jones

Now we're having a problem. We keep getting new names that aren't capitalized properly. So we can write a new method rename_with_capitalization and use alias_method_chain to resolve this:

class Person
def rename_with_capitalization(name)
rename_without_capitalization(name)
self.first_name[0,1] = self.first_name[0,1].upcase
self.last_name[0,1] = self.last_name[0,1].upcase
end

alias_method_chain :rename, :capitalization
end

Now, the old rename is called rename_without_capitalization, and rename_with_capitalization is rename. For example:

person.rename("bob smith")
person.first_name #=> Bob
person.last_name #=> Smith

person.rename_without_capitalization("tom johnson")
person.first_name #=> tom
person.last_name #=> johnson

alias_method, alias_method_chain, and self.included

When you monkey patch something you must redefine the method, because there's no super to inherit from (so you can't use the second code excerpt).

Copying the current method implementation and adding your own is just asking for trouble, so this is where alias_method comes in.

alias_method :form_for_without_cherries, :form_for

It actually creates a clone to the original method, which you can use instead of super. The fact that you can't chain monkey patches is not a bug, it's a feature.

The rails alias_method_chain method was indeed deprecated, but only because it was a poor idea from the start. However alias_method is a pure ruby method, and when used correctly can provide an elegant way of monkey patching your code, that's why I'm pretty sure it's not going away any time soon.

alias_method_chain on an HABTM attribute's setter isn't working

I ended up just using the association callback :before_add instead.

validates associated with model's error message

You can write your own custom validator, based on the code for the built-in validator.

Looking up the source code for validates_associated, we see that it uses the "AssociatedValidator". The source code for that is:

module ActiveRecord
module Validations
class AssociatedValidator < ActiveModel::EachValidator
def validate_each(record, attribute, value)
if Array.wrap(value).reject {|r| r.marked_for_destruction? || r.valid?}.any?
record.errors.add(attribute, :invalid, options.merge(:value => value))
end
end
end

module ClassMethods

def validates_associated(*attr_names)
validates_with AssociatedValidator, _merge_attributes(attr_names)
end
end
end
end

So you can use this as an example to create a custom validator that bubbles error messages like this (for instance, add this code to an initializer in config/initializers/associated_bubbling_validator.rb):

module ActiveRecord
module Validations
class AssociatedBubblingValidator < ActiveModel::EachValidator
def validate_each(record, attribute, value)
((value.kind_of?(Enumerable) || value.kind_of?(ActiveRecord::Relation)) ? value : [value]).each do |v|
unless v.valid?
v.errors.full_messages.each do |msg|
record.errors.add(attribute, msg, options.merge(:value => value))
end
end
end
end
end

module ClassMethods
def validates_associated_bubbling(*attr_names)
validates_with AssociatedBubblingValidator, _merge_attributes(attr_names)
end
end
end
end

So you can now validate like so:

class User < ActiveRecord::Base
validates_associated_bubbling :account
end

Also, be sure to add a validate: false in your has_many association, otherwise, Rails will validate the association by default and you'll end up with two error messages, one given by your new AssociatedBubblingValidator and one generic given by Rails.



Related Topics



Leave a reply



Submit