Association in a custom validation method - ruby-on-rails

I made the following class, but it didn't work correctly.
class User < ActiveRecord::Base
validate :validate_department_code, on: :create
def validate_department_code
if self.department_code.present?
department = Department_code.find_by_name(self.department_code)
user.build_participation(department: department)
else
self.errors.add(:department_code, :not_found)
end
end
end
After validation, the user is saved in DB, but the participation is not saved. So user.participation becomes nil.
How can I solve the problem?

In User.rb, add an after_create on a condition.
It should look like:
after_create :create_participation, if: :department_code.present?

Related

RoR callback after_create

I have 2 models User and Profile
class User < ApplicationRecord
has_one :profile
after_create :create_profile
end
class Profile < ApplicationRecord
validates :first_name, :last_name, presence: true
belongs_to :user
end
My problem is that
after_create: create_profile
doesn't work, because does not pass validation. Does rail have something after_create: create_profile! or after_create (validate: false): create_profile to skip validation?
After_create will work in controller not in model.
create a method in controller which gets called on after_create action.
in that method call the Model method to create a profile.
Its not good to skip the validations but if you want to, You can still do it.
In the profile model, you can add a flag to skip the validation on call from this method.
after_create :create_profile!
private
def create_profile!
profile = Profile.new(user_id: self.id)
profile.save(validate: false)
end
I tried to do this.
Another solution that has occurred is to set default values to the database.

How to prevent duplicate records being created, but all other before_create methods to run?

A Rails app has an Event and Vote model. Events should be unique.
If a User attempts to create an Event that already exists, save should be prevented, and instead a Vote should be created for the existing Event.
I can prevent the Event from being saved using a custom validation or a before_create action. However, this also prevents the create_vote_on_existing_event method from being run.
Is there a way to selectively run methods when before_create returns false?
My models look something like this
class Event
has_many :votes
before_create :check_event_is_unique
private
def check_event_is_unique
if Event.where( attributes_to_match).any?
errors.add(:base, :duplicate)
create_vote_on_existing_event
return false
end
end
def create_vote_on_existing_event
event = Event.where( attributes_to_match).last
self.user.vote_on event
end
end
class Vote
belongs_to :event
end
You need a custom validator. Something like this might be suitable:
class Event
validate :check_event_is_unique, :on => :create
after_create :create_vote_on_existing_event
def check_event_is_unique
if Event.where( attributes_to_match).any?
errors.add(:base, :duplicate)
return false
end
end
end
You can also have your after_create for other methods.
More information on custom validation methods can be found here: http://guides.rubyonrails.org/active_record_validations.html#custom-methods
EDIT:
One option is to pass validate: false to the save method. api.rubyonrails.org/classes/ActiveRecord/Validations.html
Another option is after_validation. This could call your create_vote_on_existing_event if your validation fails. The order of callbacks is as follows:
before_validation
after_validation
before_save
before_create
after_create
after_save
after_commit
after_validation is the last thing to run if validations fail, so you should be able to run some code from there.

Validates association in child class of a model

I am facing strange issue in validating presence of association in a derived class.
Class Contact < ActiveRecord::Base
has_and_belongs_to_many :things
end
Class SubContact < Contact
# validates_presence_of :things
validate :must_have_things
def must_have_things
if things.blank?
errors.add("Must select things")
end
end
end
In SubContact class, I am trying to validate presence of things but nothing is working. I have tried both custom and built in validators
How can I achieve this?
add needs an attribute. Try using:
errors.add(:base, "Must not be blank")
In this case, it is the base class but it can be any other attribute too. Mention an attribute name of the SubContract class or :base.

Is there any before_update hook for an activerecord object if the object in the child relation is saved and touch is set?

I have
class Users < ActiveRecord::Base
belongs_to :team, touch: true
end
class Team < ActiveRecord::Base
has_many :users
before_save :update_popularity
before_update :update_popularity
def popularity
#secret algorythm
end
private
def update_popularity
# This is not called
end
end
User.first.name = 'John'
When I save a user I would like to update the team popularity as well. However the before_filter doesn't seem to be invoked?
Is there any proper way for doing this?
Try this before_update :update_popularity
Update:
After reviewing the API doc of touch method here, they say:
Please note that no validation is performed and only the after_touch callback is
executed.

validate the presence of at least one association object in rails 3.2

I've one small problem, I can't get solved. I want to validate that there is at least one associated model. Like in the following
class User < ActiveRecord::Base
has_many :things
validates_presence_of :things
end
class Thing < ActiveRecord::Base
belongs_to :user
end
This works fine when I update my model via #update_attributes, but when I simply set #user.things = [], I am able to get invalid data in the database. My workaroud to solve this is to overwrite the setter method
def things=(val)
begin
if val.blank?
errors.add(:things, "not valid")
raise SomeError
end
super
rescue SomeError
false
end
end
But somehow this doesn't feel right. Isn't there a way to archive the same result via validations and/or callbacks, preferably so that #things= return false (and not val) and so that #user.things is not changed (I mean the cached #user.things, #user.things(true) should work fine anyway).
You can create a custom validator that will check the presence of things.
Instead of
validates_presence_of :things
You could do
validate :user_has_things
def user_has_things
if self.things.size == 0
errors.add("user has no thingies")
end
end

Resources