Initialize objects of Associated models - ruby-on-rails

I have three models which have been defined as follows:
Answer Sheet
class AnswerSheet < ActiveRecord::Base
has_many :answer_sections
accepts_nested_attributes for :answer_sections
end
Answer Section
class AnswerSection < ActiveRecord::Base
belongs_to :answer_sheet
has_many :answers
accepts_nested_attributes_for :answers
end
Answers
class Answers < ActiveRecord::Base
belongs_to: answer_section
end
I also have the following method defined in the AnswerSheet model
def self.build_with_answer_sections
answer_sheet = new # new should be called on the class e.g. AnswerSheet.new
4.times do |n|
answer_sheet.answer_sections.build
end
answer_sheet
end
How would I go about making it so that when I make a new instance of the the AnswerSheet, I can also generate all it's dependent models as well?

You can use the after_initialize callback
class AnswerSheet < ActiveRecord::Base
has_many :answer_sections
accepts_nested_attributes for :answer_sections
after_initialize :add_answer_section
def add_answer_section
4.times {self.answer_sections.build }
end
end
class AnswerSection < ActiveRecord::Base
belongs_to :answer_sheet
has_many :answers
accepts_nested_attributes_for :answers
after_initialize :add_answer
def add_answer
2.times {self.answers.build}
end
end

Related

rails accepts_nested_attributes_for can't update

I Using accepts_nested_attributes_for to update has_many nested tables, Why not update but insert
diaries_controller.rb
def update
#diary=Diary.find(params[:id])
if #diary.update(update_diary_params)
render_ok
else
render_err :update_error
end
end
def update_diary_params
params.require(:diary).permit(:date,:weather,:remark, :diary_pictures_attributes=> [:diary_picture,:clothing_picture,:id,:_destroy])
end
model/diary.rb
class Diary < ApplicationRecord
has_many :diary_pictures,dependent: :destroy
accepts_nested_attributes_for :diary_pictures,allow_destroy: true
end
model/diary_picture.rb
class DiaryPicture < ApplicationRecord
belongs_to :diary
validates_presence_of :diary
end
enter image description here

Cart validations for maximum items

I have 2 models, cart and line_item:
cart.rb & line_item.rb
class Cart < ActiveRecord::Base
has_many :line_items, dependent: :destroy
belongs_to :user
class LineItem < ActiveRecord::Base
belongs_to :cart
belongs_to :user
application_controller.rb
def current_cart
Cart.find(session[:cart_id])
rescue ActiveRecord::RecordNotFound
cart = current_user.cart.create
session[:cart_id] = cart.id
cart
end
How can I add validations to my cart so that user can only add 5 items maximum into their cart? At the moment I have this code but it is not working?
def maximum_items_not_more_than_5
if line_items.count > 5
errors.add(:line_items, "must be less than 5")
end
end
Here is a way, I would try :
class LineItem < ActiveRecord::Base
belongs_to :cart, validate: true # enables validation
Then inside the Cart model, write your own custom validation like :
class Cart < ActiveRecord::Base
has_many :line_items, dependent: :destroy
validate :maximum_items_not_more_than_5 # using custom validation
private
def maximum_items_not_more_than_5
if line_items.count > 5
errors.add(:base, "must be less than 5")
end
end
Why is line_item belonging to user?? Surely it would be item:
#app/models/user.rb
class User < ActiveRecord::Base
has_many :carts
end
#app/models/cart.rb
class Cart < ActiveRecord::Base
belongs_to :user
has_many :line_items, inverse_of: :cart
has_many :items, through: :line_items
validate :max_line_items
private
def max_line_items
errors.add(:tags, "Too many items in your cart!!!!!!") if line_items.size > 5
end
end
#app/models/line_item.rb
class LineItem < ActiveRecord::Base
belongs_to :cart, inverse_of: :line_items
belongs_to :item #-> surely you want to specify which item is in the cart?
end
#app/models/item.rb
class Item < ActiveRecord::Base
has_many :line_items
has_many :carts, through: :line_items
end
Validation
This is certainly in the realms of validation, specifically a custom method:
#app/models/model.rb
class Model < ActiveRecord::Base
validate :method
private
def method
## has access to all the instance attributes
end
end
I also put inverse_of into the mix.
You can see how this works here: https://stackoverflow.com/a/20283759/1143732
Specifically, it allows you to call parent / child objects from a particular model, thus allowing you to call validations & methods residing in those files.
In your case, it may be prudent to add validations to the line_item model -- specifying individual quantities or something. You can call the validations in this model directly from your cart model by setting the correct inverse_of

validate destruction of has_many association?

Models:
class Factory < ActiveRecord::Base
has_many :factory_workers
has_many :workers, through: :factory_workers
end
class FactoryWorkers < ActiveRecord::Base
belongs_to :factory
belongs_to :worker
before_destroy :union_approves?
private
def union_approves?
errors.add(:proletariat, "is never destroyed!")
false
end
end
class Worker < ActiveRecord::Base
has_many :factory_workers
has_many :factorys, through: :factory_workers
end
If I attempt to update a Factory's list of Workers via Factory, and that leads to the destruction of some FactoryWorker associations, I hope that the before_destroy hook is called, but this does not seem to be the case.
Example
Factory.create(name: 'communist paradise', worker_ids: [1, 2])
Factory.find_by(name: 'commnist paradise').update(worker_ids: [1])
# before_destroy hook is not called, proletariat must riot!
How can I ensure the before_destory hook is called when updating a record's associations?
Found what I needed: ActiveRecord provides a before_remove method on associations, so I just need to rejigger as follows:
class Factory < ActiveRecord::Base
has_and_belongs_to_many :workers, before_remove: :union_approves?
private
def union_approves?
...
end
end

Rails Has many in a belongs_to relationship

In my rails app I have the following models
class Member < ActiveRecord::Base
has_many :trainings
end
class Student < ActiveRecord::Base
belongs_to :member
has_many :trainings #maybe a through relationship here
end
class Teacher < ActiveRecord::Base
belongs_to :member
end
######edited#################
class Training < ActiveRecord::Base
belongs_to :member #only member not student nor teacher
end
#############################
Now, how can I build the trainings in my student controller
class StudentsController < ApplicationController
def new
#student = Student.new
#student.trainings.build #### This is not working
end
end
Thanks
You have to write accepts_nested_attributes_for in the model and add them in strong parameters if you are using rails 4. Like this :
class Student < ActiveRecord::Base
belongs_to :member
has_many :trainings
accepts_nested_attributes_for :trainings
end
class StudentsController < ApplicationController
def new
#student = Student.new
#student.trainings.build
end
def create
#student = Student.create(student_params)
#student.trainings.build(params[:student][:trainings])
redirect_to student_path
end
#For rails 4
def student_params
params.require(:student).permit(:id, :name, trainings_attributes: [ :id, :your fields here ])
end
end
Here is a link that will help you:
Rails 4: accepts_nested_attributes_for and mass assignment
If you've properly defined your associations, then the code in your new controller action will work (I tested it). Check and make sure your Training model exists, or that you've used the correct association name (perhaps you meant :teachers?).
app/models/student.rb
class Student < ActiveRecord::Base
has_many :trainings
end
app/models/training.rb
class Training < ActiveRecord::Base
belongs_to :student
end
app/controllers/students_controller.rb
class StudentsController < ApplicationController
def new
#student = Student.new
#student.trainings.build
end
end
Update:
Assuming these are how your associations are defined, you could build a scoped instance of Training like so:
app/models/member.rb
class Member < ActiveRecord::Base
has_many :trainings
end
app/models/student.rb
class Student < ActiveRecord::Base
delegate :trainings, to: :member
belongs_to :member
end
app/models/training.rb
class Training < ActiveRecord::Base
belongs_to :member
end
app/controllers/students_controller.rb
class StudentsController < ApplicationController
def new
#student = Student.new
#student.build_member
#student.trainings.build
end
end
Hope that helps.

Any shortcut for updating join table when creating one of the models

For example, let us say we have
class User < ActiveRecord::Base
has_many :networks, through: user_networks
has_many :user_networks
end
class Network< ActiveRecord::Base
has_many :users, through: user_networks
has_many :user_networks
end
class UserNetwork < ActiveRecord::Base
belongs_to :user
belongs_to :network
end
Is there a shortcut for doing the following in a controller:
#network = Network.create(params[:network])
UserNetwork.create(user_id: current_user.id, network_id: #network.id)
Just curious and I doubt it.
This should work:
current_user.networks.create(params[:network])
But your code implies you are not using strong_parameters, or checking the validation of your objects. Your controller should contain:
def create
#network = current_user.networks.build(network_params)
if #network.save
# good response
else
# bad response
end
end
private
def network_params
params.require(:network).permit(:list, :of, :safe, :attributes)
end

Resources