Update nested_attributes - ruby-on-rails

A course has_many students and student has_many courses
Using a json API how would we update course to assign multiple students to a course
Model
class Course < ActiveRecord::Base
has_many :course_students
has_many :students, through: course_students
accepts_nested_attributes_for :course_students
end
class Student < ActiveRecord::Base
has_many :course_students
has_many :courses, through: course_students
end
class CourseStudent < ActiveRecord::Base
belongs_to :course
belongs_to :student
end
Controller
class CoursesController < SessionsController
def update
if #course.update_attributes(course_params)
puts "students should now be added to course"
end
end
def course_params
params.require(:course).permit(:description, :status, course_students_attributes: [:id], course_jobs_attributes: [:id])
end
end
Am I on the right path?

If your relationship is many to many, you are missing the keyword through in the association declaration:
class Course < ActiveRecord::Base
has_many :students, through: :course_students
accepts_nested_attributes_for :course_students
end
class Student < ActiveRecord::Base
has_many :courses, through: :course_students
end
http://guides.rubyonrails.org/association_basics.html#the-has-many-through-association
Also be careful with accepts_nested_attributes_for, specially with validations. Here you can read more: https://robots.thoughtbot.com/accepts-nested-attributes-for-with-has-many-through

Related

Many to many relationship ActiveRecord::HasManyThroughAssociationNotFoundError

Hi I'm trying to set up a many to many relationship in my app. I have two models Count.rb
class Count < ApplicationRecord
has_many :users, through: :counts_users
end
users.rb:
class User < ApplicationRecord
has_many :counts, through: :counts_users
end
and counts_users.rb:
class CountsUser < ApplicationRecord
belongs_to :user
belongs_to :count
end
Now I can create a count
Count.new(message: 'hello')
but if I then do
Count.last.users << User.last
I get the error ActiveRecord::HasManyThroughAssociationNotFoundError: Could not find the association :counts_users in model ErrorCount
I assume I've done something wrong setting up the association, but I'm not sure what?
Your models' associations should be set up like this:
# count.rb
class Count < ApplicationRecord
has_many :counts_users
has_many :users, through: :counts_users
end
# user.rb
class User < ApplicationRecord
has_many :counts_users
has_many :counts, through: :counts_users
end
# counts_user.rb
class CountsUser < ApplicationRecord
belongs_to :user
belongs_to :count
end
See: the Rails Guides on has_many :through Association

Rails has_many association through a belongs_to polymorphic association

In my database there are 4 models
class MasterPayment < ActiveRecord::Base
has_many :payments
end
class Payment < ActiveRecord::Base
belongs_to :master_payment
belongs_to :payable, polymorphic: :true
end
class TreatmentPlan < ActiveRecord::Base
has_many :payments, as: :payable
end
class ArbitraryBillableItem < ActiveRecord::Base
has_many :payments, as: :payable
end
What i would like to do is set up an association in MasterPayment that will associate payables to master payments.
Currently, the closest i could find was setting up the master payment model as follows
class MasterPayment < ActiveRecord::Base
has_many :payments
has_many :treatment_plans, through: :payments, source: :payable, source_type: "TreatmentPlan"
has_many :arbitrary_billable_items, through: :payments, source: :payable, source_type: "ArbitraryBillableItem"
def payables
self.treatment_plans + self.arbitrary_billable_items
end
end
The only problem i have with this is that it doesn't feel like the "correct" way to do it.
The only reason i can see for rails not having a solution to this is because you would presumably have to union the tables to return it in one sql statement.
Is there an alternative way to accomplish this that will make more use of the active record associations?
This seems too simple but would it work?
def payables
self.payments.joins(:treatment_plans, :arbitrary_billable_items).distinct
end

How to create an object - has one :through

class Card < ApplicationRecord
has_one :card_rating
has_one :rating, through: :card_rating
end
class Rating < ApplicationRecord
has_many :card_ratings
has_many :cards, through: :card_ratings
end
class CardRating < ApplicationRecord
belongs_to :card
belongs_to :rating
end
I want to do something along the lines of the following:
c = card.card_rating.new
c << rating
But there doesn't seem to be any association going on at all, because already at the first statement I receive the following error:
undefined method `new' for nil:NilClass
You do not need a join table for a one to many relation:
class Card
belongs_to :rating
end
class Rating
has_many :cards
end
Rather you would use has_one :through in case the domain dictates that the relation is indirect.
class Student
belongs_to :school
has_one :headmaster, through: :school
end
class School
has_many :students
end
class Headmaster
belongs_to :school
has_many :students, through: :school
end

Struggling with has_many :through

Suppose I have 3 Models like this (not sure if this is correct):
class User < ActiveRecord::Base
has_many :lessons
has_many :points, through: :progress
end
class Progress < ActiveRecord::Base
belongs_to :user
has_many :lessons
end
class Lesson < ActiveRecord::Base
belongs_to :progress
end
(The Progress table has user_id and lesson_id fields.)
How would I make it so calling #user.points would return the amount of entries into the Progress table. Also, how would I build a relationship?
class User < ActiveRecord::Base
has_many :progresses
has_many :lessons, through: :progresses
end
class Progress < ActiveRecord::Base
belongs_to :user
belongs_to :lesson
end
class Lesson < ActiveRecord::Base
has_many :progresses
end
First, you need to set up the association for progress on your User model, so that the through association will work:
class User < ActiveRecord::Base
has_many :lessons
has_many :progress
has_many :points, through: :progress
end
Then you'll need to define a method (or relation) of points on your Progress table. Or, if you simply want a count of records, you could do: #user.points.size

Named many to many relations in Rails

How should I create following model in Rails 3.2? Project can have 1+ owners and 1+ users. Both of them are instances of class Person. I've thought about has_and_belongs_to_many but I don't know how to handle two separate collections of Persons for each Project.
You'll need a join model to represent each has-and-belongs-to-many relationship, and you would access using has-many-through as described here:
class ProjectOwnerLink < ActiveRecord::Base
belongs_to :project
belongs_to :owner, class_name: 'Person'
end
class ProjectUserLink < ActiveRecord::Base
belongs_to :project
belongs_to :user, class_name: 'Person'
end
class Project < ActiveRecord::Base
has_many :project_owner_links
has_many :owners, :through => :project_owner_links
has_many :project_user_links
has_many :users, :through => :project_user_links
end
class Person < ActiveRecord::Base
has_many :project_owner_links
has_many :owned_projects, :through => :project_owner_links, :source => :project
has_many :project_user_links
has_many :used_projects, :through => :project_user_links, :source => :project
end
You could define another model Participation that holds the type of the relationship, i.e. the role of the user. (Untested) code:
class Project < ActiveRecord::Base
has_many :participations
has_many :users, :through => :participations
def with_role(role)
includes(:participations).where('participation.role = ?', role)
end
def owners
users.with_role('owner')
end
def participants
users.with_role('participant')
end
end
 
class User < ActiveRecord::Base
has_many :participations
has_many :projects, :through => :participations
def with_role(role)
includes(:participations).where('participation.role = ?', role)
end
def projects_owned
projects.with_role('owner')
end
def projects_participating_in
projects.with_role('participant')
end
end
 
class Participation < ActiveRecord::Base
# has an attribute 'role'
belongs_to :project
belongs_to :user
end
Below is the demo application.
https://github.com/diatmpravin/habtm-demo.git
Please have a look, Let me know if you have any question?

Resources