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
How to Get a List of Files That Have Been 'Required' in Ruby
Understanding Ruby Symbol as Method Call
How to Force One Field in Ruby's CSV Output to Be Wrapped with Double-Quotes
How to Use Rspec Expectations in Irb
Get Server File Path with Paperclip
Rails: Why Images Are Not Showing in My Rails Basic App
Scientific Programming with Ruby
Differencebetween 'Include' and 'Prepend' in Ruby
What Is the Activemodel Method Attribute "_Was" Used For
Single Table Inheritance or Class Table Inheritance
Retrieve Contents of Url as String
Why Doesn't This Work If in Ruby Everything Is an Object
How to Convert a JSON String to an Object
Adding Keywords to Ruby Syntax Highlighting for Notepad++
Testing After_Commit with Rspec and Mocking
Ruby/Ror: Calling Original Method via Super()
Rspec and Shoulda - Complementary or Alternatives
Is It Possible in Rails to Check Whether a Redirect or Render Had Already Been Issued