Ruby On Rails 4, dynamically create nested association inside a nested association - ruby

I have 3 models
class Patient < ActiveRecord::Base
has_one :address, as: :person
has_many :doctors
accepts_nested_attributes_for :address, :reject_if => :all_blank, :allow_destroy => true
validates_associated :address
accepts_nested_attributes_for :doctors, :reject_if => :all_blank, :allow_destroy => true
validates_associated :doctors
end
class Doctor < ActiveRecord::Base
after_initialize :init, unless: :persisted?
has_one :address, as: :person
belongs_to :patient
accepts_nested_attributes_for :address, :reject_if => :all_blank, :allow_destroy => true
validates_associated :address
def init
self.address ||= build_address
end
end
class Address < ActiveRecord::Base
belongs_to :person, polymorphic: true
end
I am using simple_form and cacoon to handle my UI.
I had to ask Specialist initialize address on Model level, other wise address of specialist does not get initialized for cacoon.
in my controller, I initiate my Doctor and Address with
#patient.doctor.build
#patient.address ||= Address.new
However, I got an error message if every inputs were blank for specialist's address.
SQLite3::ConstraintException: NOT NULL constraint failed: addresses.line_1: INSERT INTO "addresses" ("person_type", "person_id", "created_at", "updated_at") VALUES (?, ?, ?, ?)
Does this mean it automatically generate address during save even though
accepts_nested_attributes_for :address, :reject_if => :all_blank, :allow_destroy => true
was set?
Is there any way to solve this? or is there a better way to achieve what I want?

You should not use the init method to initialise the address. Instead, you should use the :wrap_object option cocoon provides (documentation).
For instance, in your case that would become something like
link_to_add_association 'add doctor', f, :doctors, wrap_object: Proc.new {|doctor| doctor.build_address; doctor }

Related

Validate uniqueness nested model params

I have three models:
class User < ActiveRecord::Base
has_many :user_countries
accepts_nested_attributes_for :user_countries, reject_if: :all_blank
validate :user_countries
end
class UserCountry < ActiveRecord::Base
belongs_to :user
belongs_to :country
end
class Country < ActiveRecord::Base
has_many :user_countries
has_many :users, :through => :user_countries
end
In a the user creation form I can create user_countries too. How I can validate in server the uniqueness of country_id in user_countries. A user has many countries: France, United State... but not for example: France and France.
I've added this to user_countries.. but it don't work:
validates :user_id, uniqueness: {scope: :country_id, allow_blank: false}
Try this in the user_country model.
class UserCountry < ActiveRecord::Base
belongs_to :user
belongs_to :country
validates_uniqueness_of :user_id, scope: :country_id, allow_blank: false
end
Also, you need to create a migration like below to add unique indexes on database level.
add_index :user_countries, [ :user_id, :country_id ], :unique => true

Mongoid: Referencing Same Model More Than Once Through has_many

I'd like to be able to reference a model (a has_many relationship) more than once in the same model. For example, given the following models:
class MyModel
include Mongoid::Document
field :name, type: String
has_many :main_efforts, :class_name => 'Effort', as: :effortable, dependent: :delete, autosave: true
has_many :secondary_efforts, :class_name => 'Effort', as: :effortable, dependent: :delete, autosave: true
validates_presence_of :name
end
class Effort
include Mongoid::Document
field :name, type: String
belongs_to :effortable, polymorphic: true
validates_presence_of :name
end
As you can see, the Effort model is referenced twice. Originally, my Effort model wasn't polymorphic, but it seemed Mongoid was unable to determine which collection (main_efforts or secondary_efforts) the effort belonged to. As such, I made it polymorphic. After making it polymorphic, however, my main_efforts and secondary_efforts fields are always an empty array.
What is the proper way to reference a polymorphic model more than once in the same model (assuming a polymorphic model is necessary)?
Figured it out:
class MyModel
include Mongoid::Document
field :name, type: String
has_many :main_efforts, :class_name => 'Effort', dependent: :delete, autosave: true, :inverse_of => :main_effort
has_many :secondary_efforts, :class_name => 'Effort', dependent: :delete, autosave: true, :inverse_of => :secondary_effort
validates_presence_of :name
end
class Effort
include Mongoid::Document
field :name, type: String
belongs_to :main_effort, :class_name => 'Conop', :inverse_of => :main_efforts
belongs_to :secondary_effort, :class_name => 'Conop', :inverse_of => :secondary_efforts
validates_presence_of :name
end

Why is assign_attributes with array of ids for has_many association only associating one object?

I have a form where users can upload assets using ajax. This creates many Asset objects that I then want to associate with a Post object when it is created. I have a form_field named asset_ids that I update with the created Asset ids as they are created. When I create the Post object and populate its data with assign_attributes, only ONE association is created, no matter how many ids are there.
Asset model:
class Asset < ActiveRecord::Base
attr_accessible :caption, :image
belongs_to :post
has_attached_file :image, :styles => { :large => "600x600>", :medium => "300x300>", :thumb => "100x100>" }
end
Post model:
class Post < ActiveRecord::Base
attr_accessible :content, :post_date, :status, :title, :tag_list, :asset_ids, :as => :admin
has_many :assets, :dependent => :destroy
has_and_belongs_to_many :tags
validates :content, :post_date, :title, :presence => true
end
An example of the posted data hash:
{"title"=>"Test post", "status"=>"true", "post_date"=>"01/02/2013", "content"=>" Some content", "tag_list"=>"", "asset_ids"=>"97,102"}
The example above assigns only one Asset (id 97) to the new Post, when I assign_attributes like so:
#post = Post.new
#post.assign_attributes params[:post], :as => :admin
I had to make sure I was assigning the ids as an array:
#post.asset_ids = params[:post][:asset_ids].split(",")

has_many :through child and parent validations

I have a rails 3.0
has_many :X, :through => :something set up and i have a custom validator that does some custom validation on some complicated logic. I want to when you add anything to this many to many relationship both models are valid?
Project Class:
class Project < ActiveRecord::Base
has_many :assignments
has_many :users, :through => :assignments
validates :name, :presence => true
end
Assignment:
class Assignment < ActiveRecord::Base
belongs_to :project
belongs_to :user
end
User class with custom validator:
class MyCustomValidator < ActiveModel::Validator
def validate( record )
if record.projects.length > 3
record.errors[:over_worked] = "you have to many projects!"
end
end
end
class User < ActiveRecord::Base
has_many :assignments
has_many :projects, :through => :assignments
validates :name, :presence => true
validates_with MyCustomValidator
end
What i really want to do is prevent each model from invalidating the other so to say
prevent
my_user.projects << fourth_project
and
my_project.users << user_with_four_projects_already
from happening. Right now it allows the assignment and just the user becomes invalid.
class Project < ActiveRecord::Base
has_many :assignments
has_many :users, :through => :assignments
validates :name, :presence => true
validates_associated :users
end
According to the docs, users must already be assigned to Projects in order to be validated. So:
my_user.projects << fourth_project
would occur, then projects would validate the user and see that it is indeed invalid, making the project invalid as well as in the inverse example.

rails belong_to which class to choose

There is a model relation like this.
class A
belongs_to :ref_config,:class_name => 'User'
end
My question is :
the A has a attribute named flag, now i want to create a function like this:
if flag == 1, I want the class A like this belongs_to :ref_config,:class_name => 'Department and if flag == 2, i want the class A like this belongs_to :ref_config,:class_name => 'User'
How can I implement the function
Thank you!
Have a look at polymorphic associations, which will let you use the same belongs_to relation to refer to different models.
You could configure your models something like this:
class A < ActiveRecord::Base
belongs_to :ref_config, :polymorphic => true
end
class Department < ActiveRecord::Base
has_many :as, :as => :ref_config
end
class User < ActiveRecord::Base
has_many :as, :as => :ref_config
end
To set up the needed columns in the A table, use a migration like this:
class CreateAs < ActiveRecord::Migration
def self.up
create_table :as do |t|
t.string :name # or whatever other attributes A should have
t.references :ref_config, :polymorphic => true
end
end
def self.down
drop_table :as
end
end
From the little i got your question following may help you.
class A
belongs_to :department_config, :class_name => 'Department', :conditions=> flag= 1
belongs_to :user_config, :class_name => 'User', :conditions=> flag= 2
end

Resources