Multiple has_paper_trail in a model, one for :create e another one for :update - paper-trail-gem

I have the situation when in the :create scenario I need to use the :if checking one field but when in the :update or :touch scenario I need to use the :if for another field (ignoring the field checked when :create).
So, I'm trying to do this.
class MyModel < ActiveRecord::Base
has_paper_trail if: Proc.new { |mymodel| mymodel.whodunnit.present? },
on: [:create]
has_paper_trail if: Proc.new { |mymodel| mymodel.status.present? },
on: [:update, :touch]
before_create {
PaperTrail.request.whodunnit = whodunnit if whodunnit.present?
}
attr_accessor :whodunnit
end
But it is not working, what is the correct way to do this?
Thanks.

Related

validates_acceptance_of not working for a checkbox

I am trying various options for the past three hours to make a "terms and conditions" checkbox working
Here is my code
/models/user.rb
class User < ActiveRecord::Base
#validates :terms, acceptance: { accept: true } , :on => :create
validates_acceptance_of :terms, :allow_nil => false, :accept => true, :on => :create
end
this is what I am always getting
html looks like this
I added this to allow params
class ApplicationController < ActionController::Base
before_action :configure_permitted_parameters, if: :devise_controller?
# for allowing terms in signup
protected
def configure_permitted_parameters
devise_parameter_sanitizer.permit(:sign_up, keys: [:terms])
end
end
'rails', '4.2.8'
You're passing 1 as a checkbox value. It's a default for the validator. So all you need is to get rid of :accept => true option.
The true one is used only in case of validating boolean database field. As I understand you don't have such a column in users table and only want to referer to the HTML checkbox.

How to validate Rails model based on a parameter?

I have User model, and need to validate phone number attribute based on the controller param.
class User < ActiveRecord::Base
validates_presence_of :phone_number
end
This validation should validate phone_number in the Create action.
Let's say the param I should check is
params[:phone_number]
you can use before_save validation, in User model you can write
before_save :validate_phone_number
private
def validate_phome_number
self.phone_number = /some regex/
end
In self.phone_number you will get controller params by default
validate :custom_validation, :on => :create
private
def custom_validation
//whatever you want to check
end
I have tried many ways to complete this task,
I used Inheritance - Created a sub class from the User class
Call a method in the model from the controller to set the attribute and bind that attribute with the validation
Use the context option
I guess the context option is the most reliable solution for this issue i faced. So here when i set the context as :interface the model validation will trigger only based on that value
Model - User.rb
class User < ActiveRecord::Base
validates_presence_of :phone_number, on: :interface
end
Controller - users_controller.rb
#user = User.new(user_params)
#save_result = false
if params[:invitation_token] == nil
save_result = #user.save(context: :interface)
else
save_result = #user.save
end
If you use multiple options in ON:
validates :terms_and_conditions, acceptance: {accept: true}, on: [:create, :interface], unless: :child
validates :privacy_policy, acceptance: {accept: true}, on: [:create, :interface], unless: :child

validate inclusion not working on create

Okay I have quite a weird scenario that I do not know how to deal with so please bear with me as I try to explain it to you.
I have the following model.
class User < ActiveRecord::Base
Roles = { pending: 'pending_user', role2: 'role2', etc: 'etc' }
attr_accessible :role
validates :role, inclusion: {in: Roles.values}
before_create :add_pendng_role #Set user role to Roles[:pending]
end
Now the problem is when creating a record for the first time, this validation fails! For example in my controller I have the following code:
class UsersController < ActionController::Base
#user = User.new params[:user]
if #user.save # --------------- ALWAYS FAILS -------------------------------
#do something
else
#do something else
end
end
Now the reason I believe it fails is because a role is only added before_create which is called after the validations have passed. Now I know that I can't replace the before_create :add_role with before_validation :add_role because I think that it will add the role each time a validation is done. The reason I can't have that is because the user role will change in the application and I don't want to reset the role each time a validations are done on the user.
Any clues on how I could tackle this?
You could try:
before_validation :add_role, on: :create
Use *before_validation*, as explained in the rails callback guide
class User < ActiveRecord::Base
Roles = { pending: 'pending_user', role2: 'role2', etc: 'etc' }
attr_accessible :role
validates :role, inclusion: {in: Roles.values}
before_validation :add_pendng_role, on: :create #Set user role to Roles[:pending]
end
Looks like you'll be able to change before_create to before_validation if you use the :on argument:
before_validation :add_pendng_role, :on => :create

after_commit :on => :destroy In a observer-like fashion

I want to do the following:
after_commit :on => :destroy do
Advert.clean_total_active_cache
end
But in a observer-like fashion like this:
class AdvertObserver < ActiveRecord::Observer
def after_commit advert
Advert.clean_total_active_cache
end
end
It's the ":on => :destroy", that's causing me trouble, how do I specify that?
You can check if the record is not persisted and frozen:
class AdvertObserver < ActiveRecord::Observer
def after_commit advert
if not advert.persisted? and advert.frozen?
Advert.clean_total_active_cache
end
end
end

Rails: validate presence of foo unless bar == 'baz'

I'm working on a model that has two associations that need to be set when an object is created, EXCEPT in one case.
Basically, it needs to work like this.
class Example < ActiveRecord::Base
has_one :foo
has_one :bar
validates_presence_of :foo
validates_presence_of :bar, :unless => :foo == Foo.find_by_name('ThisFooDoesntLikeBars')
end
I'm not sure how to build the :unless condition here, as it needs to check whether :foo is a specific object or not.
How do you do something like this?
:unless accepts a Proc
validates_presence_of :bar, :unless => Proc.new { |ex| ex.foo == Foo.find_by_name('ThisFooDoesntLikeBars') }
:unless - Specifies a method, proc or string to call to determine if the validation should not occur (e.g. :unless => :skip_validation, or :unless => Proc.new { |user| user.signup_step <= 2 }). The method, proc or string should return or evaluate to a true or false value.
http://api.rubyonrails.org/classes/ActiveRecord/Validations/ClassMethods.html
How about the following:
class Example < ActiveRecord::Base
has_one :foo
has_one :bar
validates_presence_of :foo
validates_presence_of :bar, :unless => Proc.new { |example| example.foo == Foo.find_by_name('ThisFooDoesntLikeBars') }
end

Resources