custom validation with client side validation - ruby-on-rails

have two models,
class Quote < ActiveRecord::Base
attr_accessible :quote_date
validates :quote_date, :presence => true
end
and
class Invoice < ActiveRecord::Base
attr_accessible :invoice_date
validates :invoice_date, :presence => true
validate :invoice_date_lesser
belongs_to :quote
private
def invoice_date_lesser
if invoive_date < quote_date
errors.add(:invoice_date, 'invoice date invalid')
end
end
end
would be of great help if i could get some solution as to how to do this validation
and custom validation with client-side validation

I hope I understand your questions.
You want to know how to get a validation that using a nested resource
You want to know how to make that validation pass through to client side validation
For validations: add the reference to the associated model
def invoice_date_lesser
if invoive_date < quote.quote_date
errors.add(:invoice_date, 'invoice date invalid')
end
end
For client side validations: add validate => true in your form_for
form_for #model, :validate => true do |f|

Related

how to validate rails form if will split form in multi tab?

we have rails model campaign and it had has_many location and camapign also has many groups and group has many tags
we like to have All validation must with server side.
My models are:
class Camapign < ActiveRecord::Base
has_many :locations
has_many :groups
attr_writer :current_tab
validates :name, :presence => true
validates :event_date, :presence => true
end
class Location < ActiveRecord::Base
validates :name, :presence => true
end
class Group < ActiveRecord::Base
has_many :tags
validates :name, :presence => true
validates :industry, :presence => true
end
class Tag < ActiveRecord::Base
validates :name, :presence => true
end
When i am creating Camapign i was creating Camapign with validate false and my view is in different tabs/portlet.
I need to validate only field which i have showed on form and if its not valid then it should navigate to proper error to respected tabs.
on first tab i have campaign name and locations
on second tab i have Groups name and tabs
i like to save all tabs details in to database with respected progress on tabs and at end conform and publish all details but i like to validate details ate intermediate tabs that i have on modal.
i have all operation on Camapign model with relational insert and i am tracking with current_tab attribute.
I able to validate Camapign modal field with current_tab values but not able to validate with other relational modal.
we not like to use any additional gem like wicked i like to make as simple as standard code so we have less dependency.
Please help us to validate form based on tabs and hoe to display error on tabs.
we can validation by before save events
class Camapign < ActiveRecord::Base
has_many :locations
has_many :groups
attr_writer :current_tab
validates :name, :presence => true
validates :event_date, :presence => true
attr_writer :current_step # for access current tabs
with_options :if => Proc.new { |campaign| campaign.current_step == "location"} do |step|
step.after_validation :validate_location_name
end
def validate_location_name
self.locations.each do |location|
if !location.name.present?
location.errors.add(:name,"Invalid location")
errors.add(:name,"Invalid location")
end
end
end
end

Rails validates_uniqueness_of and scope - working only on update

I have these 3 classes:
class Profile < ActiveRecord::Base
end
class Subject < ActiveRecord::Base
end
class ProfileSubject < ActiveRecord::Base
belongs_to :profile
belongs_to :subject
validates_uniqueness_of :subject_id, scope: :profile_id
end
And this validates_uniqueness_of works great when I update my profile with his associated collection of ProfileSubject. But, on create action - it is not validated this uniqueness. I thought, maybe this is because when I create object I do not have profile_id yet...and I tried add my own token for models, which I can use for connect them and validation by it (use it on scope for validates_uniqueness_of). Ad I know now, it was not useful and not working.
Could you help me...why this standard validation works OK on update action..but does not work on create action.
Creation code is standard, something like this:
#profile = Profile.new(profile_params)
if #profile.save
# ...
else
# ...
end
Use:
validates_associated :subject, :profile
validates :subject, :profile, :presence => true
In stead of:
validates_uniqueness_of :subject_id, scope: :profile_id

Upgrading attr_accessible from Rails 3 to Rails 4

I'm trying to systematically upgrade from rails 3 to rails 4 and all of my 25 models are based on attr_accessor! So before getting into that can anyone provide me a simple example on how to do this. I've read the documentation and other topics but it's not clear on how to do it since this is my first upgrade Rodeo.
class Settings < ActiveRecord::Base
image_accessor :favicon
attr_accessible :company_name, :show_hot_jobs, :show_students, :subheading, :show_testimonials, :show_on_boarding, :max_concurrent_applications
attr_accessible :image_uid, :max_concurrent_application_groups
attr_accessible :primary_color, :white_color, :gray_color, :opacity, :locale, :lang_nl, :lang_fr, :lang_de, :lang_en, :privacy_page
attr_accessible :show_evp, :show_contact_person, :show_jobs_for_you
attr_accessible :favicon, :favicon_uid, :remove_favicon, :retained_favicon
attr_accessible :home_url, :show_correspondence, :show_appointment
attr_accessible :sliderone_uid, :slidertwo_uid, :sliderthree_uid, :sliderfour_uid, :sliderfive_uid
attr_accessible :sliderone_link, :slidertwo_link, :sliderthree_link, :sliderfour_link, :sliderfive_link
attr_accessible :sliderone_testoverview, :slidertwo_testoverview, :sliderthree_testoverview, :sliderfour_testoverview, :sliderfive_testoverview
attr_accessible :sliderone_page, :slidertwo_page, :sliderthree_page, :sliderfour_page, :sliderfive_page
validate :any_lang_present?
validates :max_concurrent_applications, :numericality => { :greater_than_equal_to => 1 }
validates :max_concurrent_application_groups, :numericality => { :greater_than_equal_to => 1 }
# Fav Icon Validation
validates_property :ext, of: :favicon, :in => ['ico', 'png', 'gif']
has_paper_trail
has_many :setting_translations, :foreign_key => :setting_id
accepts_nested_attributes_for :setting_translations, :allow_destroy => true, :reject_if => :all_blank
attr_accessible :setting_translations_attributes, :allow_destroy => true
translates :subheading, :company_name, :image_uid, :home_url, :sliderone_uid, :slidertwo_uid, :sliderthree_uid, :sliderfour_uid, :sliderfive_uid
translates :sliderone_link, :slidertwo_link, :sliderthree_link, :sliderfour_link, :sliderfive_link
translates :sliderone_testoverview, :slidertwo_testoverview, :sliderthree_testoverview, :sliderfour_testoverview, :sliderfive_testoverview
translates :sliderone_page, :slidertwo_page, :sliderthree_page, :sliderfour_page, :sliderfive_page
attr_accessible can be converted like so:
From
class Settings
attr_accessible :home_url
accepts_nested_attributes_for :setting_translations
end
class SettingTranslation
attr_accessible :etc
end
To
class SettingsController
def create
#settings = Settings.new(settings_params)
# ...
end
private
def settings_params
params.require(:settings).permit(
:home_url,
:setting_translations_attributes => [:id, :_destroy, :etc]
)
end
end
Note, you have to include :_destroy if you want to allow destroy on that model (:allow_destroy => true), and you have to include all attributes that should be accessible from any nested attributes. Though you remove attr_accessible when you've permitted, you do not remove accepts_nested_attributes_for.
Just remove attr_accessible from model. and add permit params according to need in controller.
like below :
class SupportTicketsController < ApplicationController
def create
#support_ticket = SupportTicket.create(house_params)
......
end
private
def house_params
params.require(:support_ticket).permit(:subject, :message, ....)
end
end
and if you don't want to make this much changes then add "protected_attributes" gem https://github.com/rails/protected_attributes in your gemfile And everything would work as before.

How to use default and custom validators together? How to define their order?

This is my model class:
class Availability < ActiveRecord::Base
attr_accessible :beginning_date, :end_date
validates :beginning_date, :end_date :presence => true
# custom validators
validate :dates_cant_be_in_the_past
def dates_cant_be_in_the_past
if Date.parse(beginning_date) < Date.today
errors.add(:beginning_date, "cant be in the past")
end
if Date.parse(end_date) < Date.today
errors.add(:end_date, "cant be in the past")
end
end
end
Now two things should happen: At first validate the presence of the beginning_date and end_date attributes and than run my dates_cant_be_in_the_pastvalidator.
Sadly this approach doesn't work. If I leave a field empty the Date.parsemethod throws an exception, because the argument is obviously empty.
Is it possible to define the order of default and custom validations? Or do I have to implement the presence validator myself, so I would do something like:
validate :dates_cant_be_blank, :dates_cant_be_in_the_past
The guide at least says:
You can pass more than one symbol for each class method and the respective validations will be run in the same order as they were registered.
Thank in advance
It's much simpler if you create a validator for that:
class DateValidator < ActiveModel::EachValidator
def validate_each(record, attribute, value)
if Date.parse(value) < Date.today
record.errors.add(attribute, "cant be in the past")
end
end
end
And at your model you would use it like this:
class Availability < ActiveRecord::Base
attr_accessible :beginning_date, :end_date
validates :beginning_date, :end_date :presence => true
validates :beginning_date, :end_date, :date => true, :allow_blank => true
end
The :allow_blank piece if the one prevents the validation from running if the value is empty. Using a real validator object also removes the code form your model making it much simpler and removing the duplication you currently have.
You could try something like this
class Availability < ActiveRecord::Base
attr_accessible :beginning_date, :end_date
validates :beginning_date, :end_date : presence => true
# custom validators
validate :valid_dates
def valid_dates
if valid_string(beginning_date)
errors.add(:beginning_date, "Can't be in the past") unless Date.parse(beginning_date) > Date.today
end
if valid_string(end_date)
errors.add(:end_date, "Can't be in the past") unless Date.parse(end_date) > Date.today
end
end
def valid_string(test_value)
test.value.is_a? String
end
end

Rails 3 association error: undefined method

I've been puzzling over this for quite some time now and can't figure it out.
I've got 2 models:
class Vehicle < ActiveRecord::Base
attr_accessible :year, :capacity,
:size, :body, :model_id, :maker_id, :parameters_attributes
validates :year, numericality: { greater_than: 1900 }
validates :year, :capacity, :size, :body, presence: true
belongs_to :model
belongs_to :maker
has_many :parameters
accepts_nested_attributes_for :parameters
end
and
class Parameter < ActiveRecord::Base
attr_accessible :tag, :value
validates :tag, :value, presence: true
belongs_to :vehicle
end
in new vehicle view i've got:
= form_for [:admin, #vehicle], html: { multipart: true } do |f|
=# some other stuff in between
= f.text_field :value, size: 4
I get this error
undefined method `value'
Just can't seem to get it working. Help, anyone?
EDIT
routes.rb
resources :vehicles
resources :parameters
resources :makers do
resources :models
end
If you are using nested form, you should have something like
f.fields_for :parameters do |parameter|
and than:
parameter.text_field :value, size: 4
Also, remember to create the some parameters in the controller, for example:
def new
#vehicle = Vehicle.new
2.times { #vehicle.parameters.build } #it will create 2 parameters
...
end
f refers to #vehicle, it seems only Parameter bears this field. That's why it fails.
Sidenotes:
In Vehicle you have accepts_nested_attributes_for :parameters but you don't have parameters_attributes in the attr_accessible, can't be good.
If you want to call the relationship in the form consider using fields_for
Ok, I've made a mess of things.
Firstly I've been trying to
def new
#vehicle = #vehicle.parameters.build
end
hence the error undefined method. After a while I got to the correct syntax, which is the one gabrielhilal added after a while.
def new
#vehicle = Vehicle.new
#vehicle.parameters.build
end
No matter ;) Still had problems, because after clicking "create" he wouldn't add records in the database. Turned out that I've set the validates presence: true for tag, but didn't assign any value to it. After fixing that, it worked like a charm. Thanks a lot for all the help.
On to the next puzzle.

Resources