How to make sure child object is valid while saving parent? - ruby-on-rails

let say that I have two class
class User
attr_accessible :name
has_one :address
validates :name, :presence => true
validates_associated :address
end
class Address
attr_accessible :country, :user_id
belongs_to :user
validates :country, :presence => true
validates :user, :presence => true
end
Now when i try to create invalid Address then it fails(which is good)
a = Address.new
a.valid? #=> false
But when i build User with invalid Address then it pass(which is bad)
u = User.first
u.build_address
u.valid? #=> true
u.save #=> true
Due to this User has Address with country => nil.
How can i tell Rails to not save Address if its invalid?
FIXED: I fixed this by adding follow line to the code. Thank you everyone.
validates_associated :address, :if => :address

class User
attr_accessible :name
has_one :address, :validate => true
validates :name, :presence => true
validates_associated :address
end

You need to also validate that an Address is actually present for User:
class User < ActiveRecord::Base
validates :address, :associated => true, :presence => true
end
With that in place, I get:
>> u = User.first
=> #<User id: 1, name: "Bob", created_at: "2013-10-09 15:17:21", updated_at: "2013-10-09 15:17:21">
>> u.build_address
=> #<Address id: nil, user_id: 1, country: nil, created_at: nil, updated_at: nil>
>> u.valid?
=> false
>> u.errors
=> #<ActiveModel::Errors:0x007fe1d6919b18 #base=#<User id: 1, name: "Bob", created_at: "2013-10-09 15:17:21", updated_at: "2013-10-09 15:17:21">, #messages={:address=>["is invalid"]}>
>> u.address.errors
=> #<ActiveModel::Errors:0x007fe1d69197a8 #base=#<Address id: nil, user_id: 1, country: nil, created_at: nil, updated_at: nil>, #messages={:country=>["can't be blank"]}>

Related

ActiveRecord ignores validate

Heya im pulling my hair out right now
class Referal < ApplicationRecord
validates :pax, :presence => true
validates :customer_email, presence: true
default_scope -> { order('created_at DESC') }
self.implicit_order_column = "created_at"
belongs_to :referer, class_name: "User"
belongs_to :customer, class_name: "User"
belongs_to :business
<Referal:0x000055f8a468b058
id: nil,
state: nil,
handle: nil,
sec_code: nil,
pax: nil,
booking_date_time: nil,
business_id: "224cd62b-3d29-41ca-a1be-f308815514b2",
customer_id: nil,
referer_id: "cdfb1861-d5e4-4650-9783-4189cffde6bd",
customer_email: nil,
customer_mobile: nil,
customer_last_name: nil,
customer_first_name: nil,
created_at: nil,
updated_at: nil>
x.valid?
=> true
i tried multiple ways but it seems since i have multiple FK's in the model it only validates the ft for Business and Referer
how do i enforce the validator for additional fields? thanks

Rails rolify gem /assosiation issue

I use rolify gem with devise for AdminUser
my Roles table
class RolifyCreateRoles < ActiveRecord::Migration
def change
create_table(:roles) do |t|
t.string :name
t.references :resource, :polymorphic => true
t.timestamps
end
create_table(:admin_users_roles, :id => false) do |t|
t.references :admin_user
t.references :role
end
add_index(:roles, :name)
add_index(:roles, [ :name, :resource_type, :resource_id ])
add_index(:admin_users_roles, [ :admin_user_id, :role_id ])
end
end
model 'Role'
class Role < ActiveRecord::Base
has_and_belongs_to_many :admin_users, :join_table => :admin_users_roles
belongs_to :resource,
:polymorphic => true
validates :resource_type,
:inclusion => { :in => Rolify.resource_types },
:allow_nil => true
scopify
end
my issue is when i want to get users witch belong to role it gives empty array instead of my adminuser object
u = AdminUser.first
u.add_role(:admin)
u.roles => #<Role id: 1, name: "admin", admin_user_id: 1, resource_id: nil, resource_type: nil, created_at: "2016-06-16 15:03:33", updated_at: "2016-06-17 09:04:30">
and when i do
Role.first=> #<Role id: 1, name: "admin", admin_user_id: 1, resource_id: nil, resource_type: nil, created_at: "2016-06-16 15:03:33", updated_at: "2016-06-17 09:29:32">
Role.first.admin_users => []
To check if a user has a global role:
user = User.find(1)
user.add_role :admin # sets a global role
user.has_role? :admin
=> true
Or to check at instance level In your case
u = AdminUser.first
u.add_role(:admin)
> Role.first=> #<Role id: 1, name: "admin", admin_user_id: 1,
> resource_id: nil, resource_type: nil, created_at: "2016-06-16
> 15:03:33", updated_at: "2016-06-17 09:29:32">
Instead of doing this => Role.first.admin_users => []
Try
u = AdminUser.first
u.roles
Rolify has a pretty clear documentation
Rolify
oh i fixed it by changing relation in my admin_user model
from has_many to has_and_belongs_to_many :roles

Why aren't parameters populating a new instance of a class?

I am submitting a form into a CorporateContactFormsController. I can see the parameters are being passed but they are not being added to the instantiated class.
def create
#contact_form = CorporateContactForm.new(corporate_contact_form_params)
raise
end
private
def corporate_contact_form_params
params.require(:corporate_contact_form).permit(:firstname, :surname, :contact_number, :email, :company_name, :method_of_payment, :number_of_employees, :comments, :contact_type)
end
This is from better-errors gem
>> corporate_contact_form_params
=> {"firstname"=>"qwertyui", "surname"=>"wertyuio", "contact_number"=>"wertyuio", "email"=>"qwdqwd#iugh.com", "company_name"=>"wqedfwefwef", "method_of_payment"=>"Other", "number_of_employees"=>"1-50", "comments"=>"qwdqwdqwdqwdqwdqwdwqd", "contact_type"=>"employee"}
>> #contact_form = CorporateContactForm.new(corporate_contact_form_params)
=> #<CorporateContactForm id: nil, contact_type: nil, firstname: nil, surname: nil, contact_number: nil, email: nil, company_name: nil, company_website: nil, position_in_company: nil, location: nil, number_of_employees: nil, method_of_payment: nil, comments: nil, created_at: nil, updated_at: nil>
Why aren't the parameters populating the new instance of the class?
I am using rails 4.0
update
model
class CorporateContactForm < ActiveRecord::Base
EMPLOYEE = 'employee'
EMPLOYER = 'employer'
CONTACT_TYPE = [EMPLOYEE, EMPLOYER]
ONE_TO_FIFITY = "1-50"
FIFTY_TO_ONEHUNDRED = "50-100"
ONEHUNDRED_OR_MORE = "100+"
EMPLOYEE_COUNT = [ONE_TO_FIFITY, FIFTY_TO_ONEHUNDRED, ONEHUNDRED_OR_MORE]
OTHER = "Other"
COMPANY = "Company funded"
METHOD_OF_PAYMENT = [COMPANY, OTHER]
validates :contact_type, inclusion: CONTACT_TYPE, presence: true
validates :number_of_employees, inclusion: EMPLOYEE_COUNT, presence: true
validates :firstname, presence: :true
validates :email, presence: :true
validates :company_name, presence: :true
validates :email, presence: :true
validate :blanks_to_nils
private
def blanks_to_nils
blank_to_nil :surname
blank_to_nil :contact_number
blank_to_nil :position_in_company
blank_to_nil :location
blank_to_nil :method_of_payment
blank_to_nil :comments
end

Cannot get accepts_nested_attributes to work in rails 3

This might be a case of me being blind…
Somehow I cannot get my layout_positions_attributes to arrive at layout_positions
l = Layout.new
…
[17] pry(main)> l.layout_positions
=> []
[18] pry(main)> l.layout_positions_attributes=[{:name=>'xxx'}]
=> [{:name=>"xxx"}]
[19] pry(main)> l.layout_positions
=> [] # WTF!
[20] pry(main)> l.layout_positions.build({:name=>'xxx'})
=> #<LayoutPosition id: nil, name: "xxx", active: true, columns: nil, rows: nil, layout_id: nil, pos: -1>
[21] pry(main)> l.layout_positions
=> [#<LayoutPosition id: nil, name: "xxx", active: true, columns: nil, rows: nil, layout_id: nil, pos: −1>]
The parent class:
class Layout < ActiveRecord::Base
attr_accessible :name, :active, :layout_positions_attributes
has_many :layout_positions
accepts_nested_attributes_for :layout_positions,
:reject_if => lambda { |a| a[:content].blank? },
:allow_destroy => true
validates_presence_of :name
end
And where the attributes should go…
class LayoutPosition < ActiveRecord::Base
attr_accessible :name, :active, :columns, :rows, :pos
belongs_to :layout
validates_presence_of :name
end
You're telling it to reject it if the content for the layout_position object is blank. In your example, above "WTF", you're not passing through any content. Therefore this is deleting the attributes.
Calling build doesn't rely on accepts_nested_attributes_for and so will work just fine.

Is there a more efficient way to create an ActiveRecord relationship on a class that references itself through another table?

I apologize if the question title is confusing. I have the following situation: I have a Person model which stores people in the standard way in the people table.
I need to add a has_many relationship for emergency_contacts on the Person model. I tried doing this in the following way:
Migrations:
create_table :people do |t|
t.string :first
t.string :middle
t.string :last
t.timestamps
end
create_table :emergency_contacts, :id => false do |t|
t.integer :person_id
t.integer :emergency_contact_id
t.timestamps
end
Models:
class Person < ActiveRecord::Base
has_many :emergency_contacts
validates :first, :presence => true
validates :last, :presence => true
end
class EmergencyContact < ActiveRecord::Base
belongs_to :person
has_one :person, :foreign_key => 'emergency_contact_id'
end
This allows me to do:
ruby-1.9.2-p180 :001 > p = Person.new(first: "John", last: "Doe")
=> #<Person id: nil, first: "John", middle: nil, last: "Doe", created_at: nil, updated_at: nil>
ruby-1.9.2-p180 :002 > ec = EmergencyContact.new
=> #<EmergencyContact person_id: nil, emergency_contact_id: nil, created_at: nil, updated_at: nil>
ruby-1.9.2-p180 :003 > ec.emergency_contact = Person.new(first: "Peter", last: "Griffin")
=> #<Person id: nil, first: "Peter", middle: nil, last: "Griffin", created_at: nil, updated_at: nil>
ruby-1.9.2-p180 :004 > p.emergency_contacts << ec
=> [#<EmergencyContact person_id: nil, emergency_contact_id: nil, created_at: nil, updated_at: nil>]
ruby-1.9.2-p180 :005 > p.save!
=> true
However, I don't feel the EmergencyContact model should have to be there, since I am really just referencing a Person model anyway.
Is there a way to remove this "middle-man" model, so that I can just do something like:
p = Person.new(first: "John", last: "Doe")
p.emergency_contacts << Person.new(first: "Peter", last: "Griffin")
I'd really use self referential associations for this kind of purpose.
Se tutorial here: http://railscasts.com/episodes/163-self-referential-association

Resources