Rails Has many in a belongs_to relationship - ruby-on-rails

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.

Related

How to save throught model with extra field?

I have three models Company, User and Division
User have many Division for different Companies
I need to determine in what company owns Divisions
So I build has_many :through association between Users and Divisions
Model UsersDivision have this fields id|user_id|division_id|company_id but when I update User model rails delete old records and create new without company_id field How i can update model UsersDivision and merge company_id ?
Callback?
class UsersDivision < ActiveRecord::Base
after_update :set_company
belongs_to :user
belongs_to :division
belongs_to :company
validates :user_id, :division_id, presence: true
private
def set_company(company)
self.company_id = company
end
end
or in the controller?
class UsersController < ApplicationController
def update
#company = Company.find(params[:company_id])
#user = User.find(params[:id])
if #user.update(user_params)
redirect_to :back
end
end
end
How to merge company_id when create UsersDivision record?
So I build has_many :through association between Users and Divisions
I would expect there to be a table for Divisions, and then a table for CompanyDivisions, and then we can associate users to that.
Here's how I would have it set up:
#app/models/user.rb
class User < ActiveRecord::Base
has_many :user_divisions
has_many :divisions, through: :user_divisions
has_many :company_divisions, through: :user_divisions
has_many :companies, through: :company_divisions
end
#app/models/user_division.rb
class UserDivision < ActiveRecord::Base
belongs_to :user
belongs_to :company_division
end
#app/models/company.rb
class Company < ActiveRecord::Base
has_many :company_divisions
has_many :divisions, through: :company_divisions
end
#app/models/company_division.rb
class CompanyDivision < ActiveRecord::Base
belongs_to :company
belongs_to :division
end
#app/models/division.rb
class Division < ActiveRecord::Base
has_many :company_divisions
has_many :companies, through: :company_divisions
end
This is very bloated, but should give you the ability to call:
#user.divisions
#user.divisions.each do |division|
division.companies.first
How to merge company_id when create UsersDivision record
This will depend on several factors:
params hash
How your associations are set up
I don't have your params hash, but I do have your current code:
class UsersController < ApplicationController
def update
#company = Company.find params[:company_id]
#user = User.find params[:id]
redirect_to :back if #user.update user_params
end
private
def user_params
params.require(___).permit(___).merge(company_id: #company.id)
end
end

Rials:When we use fields_for, how to initiate association_build if we are not sure how many association should be created?

In such case:
class User < ActiveRecord::Base
has_many :companies
accepts_nested_attributes_for :companies
end
class Company < ActiveRecord::Base
belongs_to :users
end
This is nomal case, we're sure how many association we should create:
# user_controller
def new
#user = User.new
2.times { #user.companies.build }
end
But what if we don't know how many association should be created?

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

Model association that spans across parent app and engine

I'm making a Rails engine that makes reference to the current_user in a controller like so:
require_dependency "lesson_notes/application_controller"
module LessonNotes
class NotesController < ApplicationController
def index
if current_user
#notes = Note.where(student: current_user) if current_user.user_type.name == "student"
#notes = Note.where(teacher: current_user) if current_user.user_type.name == "teacher"
end
end
end
end
This is quite verbose and it would seem I could do something like this instead:
require_dependency "lesson_notes/application_controller"
module LessonNotes
class NotesController < ApplicationController
def index
#notes = current_user.notes if current_user
end
end
end
However, the user model exists in the parent app, not the engine.
In the Note model I have this to define the belongs_to association:
module LessonNotes
class Note < ActiveRecord::Base
belongs_to :student, class_name: "::User"
belongs_to :teacher, class_name: "::User"
end
end
How would I define the other side of the association - the has_many - in the User model?
This is how I ended up doing it...
In the parent app:
class User < ActiveRecord::Base
has_many :notes, class_name: LessonNotes::Engine::Note, foreign_key: "teacher_id"
end

Initialize objects of Associated models

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

Resources