Removing or Overriding an Activerecord Validation Added by a Superclass or Mixin

Removing or overriding an ActiveRecord validation added by a superclass or mixin

I ended up "solving" the problem with the following hack:

  1. look for an error on the :email attribute of type :taken
  2. check if the email is unique for this account (which is the validation I wanted to do)
  3. remove the error if the email is unique for this account.

Sounds reasonable until you read the code and discover how I remove an error. ActiveRecord::Errors has no methods to remove errors once added, so I have to grab hold of it's internals and do it myself. Super duper mega ugly.

This is the code:

def validate
super
remove_spurious_email_taken_error!(errors)
end

def remove_spurious_email_taken_error!(errors)
errors.each_error do |attribute, error|
if error.attribute == :email && error.type == :taken && email_unique_for_account?
errors_hash = errors.instance_variable_get(:@errors)
if Array == errors_hash[attribute] && errors_hash[attribute].size > 1
errors_hash[attribute].delete_at(errors_hash[attribute].index(error))
else
errors_hash.delete(attribute)
end
end
end
end

def email_unique_for_account?
match = account.users.find_by_email(email)
match.nil? or match == self
end

If anyone knows of a better way, I would be very grateful.

Overriding routes in the Clearance gem

Overriding the layouts is simpler than this: See: https://github.com/thoughtbot/clearance#overriding-layouts

Clearance::PasswordsController.layout 'my_passwords_layout'
Clearance::SessionsController.layout 'my_sessions_layout'
Clearance::UsersController.layout 'my_admin_layout'

Access previous value of association on record update

Could you use ActiveModel::Dirty? Something like this:

def Event < ActiveRecord::Base
validates :no_invitees_removed

def no_invitees_removed
if invitees.changed? && (invitees - invitees_was).present?
# ... add an error or re-add the missing invitees
end
end
end

Edit: I didn't notice that the OP already discounted ActiveModel::Dirty since it doesn't work on associations. My bad.

Another possibility is overriding the invited_user_ids= method to append the existing user IDs to the given array:

class Event < ActiveRecord::Base
# ...

def invited_user_ids_with_guard=(ids)
self.invited_user_ids_without_guard = self.invited_user_ids.concat(ids).uniq
end
alias_method_chain :invited_user_ids=, :guard
end

This should still work for you since update_attributes ultimately calls the individual attribute= methods.


Edit: @corsen asked in a comment why I used alias_method_chain instead of super in this example.

Calling super only works when you're overriding a method that's defined further up the inheritance chain. Mixing in a module or inheriting from another class provides a means to do this. That module or class doesn't directly "add" methods to the deriving class. Instead, it inserts itself in that class's inheritance chain. Then you can redefine methods in the deriving class without destroying the original definition of the methods (because they're still in the superclass/module).

In this case, invited_user_ids is not defined on any ancestor of Event. It's defined through metaprogramming directly on the Event class as a part of ActiveRecord. Calling super within invited_user_ids will result in a NoMethodError because it has no superclass definition, and redefining the method loses its original definition. So alias_method_chain is really the simplest way to acheive super-like behavior in this situation.

Sometimes alias_method_chain is overkill and pollutes your namespace and makes it hard to follow a stack trace. But sometimes it's the best way to change the behavior of a method without losing the original behavior. You just need to understand the difference in order to know which is appropriate.

Prevent STI when inheriting from an ActiveRecord model

You can achieve this by disabling the inheritance_column for the model, like so:

class AnotherSection < Section
# disable STI
self.inheritance_column = :_type_disabled

end

SharePoint Custom Page-Library & PageLayout

I would like to comment on one thing. Looks like IgnoreIfAlreadyExists="TRUE" is not working properly refer to this link, may be reverting the value to FALSE should help.

<File Url="CustomPage.aspx" Type="GhostableInLibrary" IgnoreIfAlreadyExists="TRUE" >


Related Topics



Leave a reply



Submit