Deleting the through association record when deassociating - ruby-on-rails

In a Rails 6.1 app, I have a standard has_many through association
class Enrollment < ApplicationRecord
belongs_to :topic
belongs_to :job_description, optional: true
end
class Topic < ApplicationRecord
has_many :enrollments
has_many :job_descriptions, through: :enrollments
end
class JobDescription < ApplicationRecord
has_many :enrollments
has_many :topics, through: :enrollments
end
Now, when updating a topic (removing a job description)
#topic.job_descriptions = [...]
#topic.save
The topic_id in the enrollments having the job_description_id no longer associated with the topic is set to NULL.
Is there a way to delete the row instead?

try changing
has_many :job_descriptions, through: :enrollments
to
has_many :job_descriptions, through: :enrollments, dependent: :destroy

Related

Unable to remove association which is read only

I have 3 tables
class Product < ApplicationRecord
has_many :accessories
has_many :product_attribute_categories, through: :accessories, dependent: :destroy
end
class Accessory < ApplicationRecord
belongs_to :product
belongs_to :product_attribute_category
end
class ProductAttributeCategory < ApplicationRecord
has_many :accessories, dependent: :destroy
has_many :products, through: :accessories
has_many :product_attributes, dependent: :destroy
now when I try to delete a ProductAttributeCategory, I want all the accessories that it is associated with to be deleted. So it wont return any errors.
However it returns Accessory is marked as readonly. So I'm wondering if what I'm doing is not optimal and what I should do instead.

has_many of the same table through several others

What am trying to do is:
i have a User model and i have a Task model
Task has 2 types of users Owners and Supervisors all of them are users !
so what i have so far is:
Task Model
class Task < ActiveRecord::Base
has_many :task_owners, dependent: :destroy
has_many :task_supervisors, dependent: :destroy
has_many :users, through: :task_owners
has_many :users, through: :task_supervisors
end
TaskSupervisor Model
class TaskSupervisor < ActiveRecord::Base
belongs_to :task
belongs_to :user
end
TaskOwner Model
class TaskOwner < ActiveRecord::Base
belongs_to :task
belongs_to :user
end
and finally the User Model
class User < ActiveRecord::Base
has_many :task_owners
has_many :task_supervisors
has_many :tasks, through: :task_owners
has_many :tasks, through: :task_supervisors
end
now as you can imagine ... my problem is when i get a task and retrieve the users i only get one of my associations ... what i need is a way to change the getters name or identify them some how basically to be able to say something like
task.owners
task.supervisors
class Task < ActiveRecord::Base
has_many :task_owners, dependent: :destroy
has_many :task_supervisors, dependent: :destroy
has_many :owners, through: :task_owners, source: :users
has_many :supervisors, through: :task_supervisors, source: :users
end
You should be able to do this.
Then you should get your task.owners and task.supervisors
Edit:
You will need to change your user model to
class User < ActiveRecord::Base
has_many :task_owners
has_many :task_supervisors
has_many :owned_tasks, through: :task_owners, source: :tasks
has_many :supervised_tasks, through: :task_supervisors, source: :tasks
end

Two has_many throughs to the same model Rails

Models:
class User < ActiveRecord::Base
has_many :reports
has_many :social_accounts
has_one :api_client
has_many :integrations
has_many :profiles, through: :integrations
has_many :tags
has_many :profiles, through: :tags
end
class Tag < ActiveRecord::Base
belongs_to :user
belongs_to :profile
end
class Profile < ActiveRecord::Base
has_many :integration_profiles
has_many :integrations, through: :integration_profiles
has_many :users, through: :integrations
belongs_to :api_client
has_many :tags
ene
At times I want to retrieve all of the user's profiles through the integrations and other times through tags. How?
The answer:
has_many :profiles_tagged, through: :tags, source: :profile
On the User model

Rails belongs_to through association

I'm trying to add a new model to an existing model mesh. The existing one works perfectly but I can't get the new one to work properly and am wondering if the association is able to work the way I'm trying to make it work. Update: As I just got asked: belongs_to through was something I've read while gooling about the problem. If it doesn't exist, would has_one through be the correct way? I tried it as well but it also didn't work.
Here is the existing mesh:
class Course
has_many :users, through: :enrollments
has_many :enrollments
end
class User
has_many :courses, through: :enrollments
has_many :enrollments
end
class Enrollment
belongs_to :course
belongs_to :user
# has fields :user_id, :course_id
end
Now a user should be able to rate a course he's completed. (If he has, there is an enrollment with his id and a course id.) I thought it would be best to write it as follows:
class Course
has_many :users, through: :enrollments
has_many :enrollments
has_many :ratings, through: :enrollments
end
class User
has_many :courses, through: :enrollments
has_many :enrollments
has_many :ratings, through: :enrollments
end
class Enrollment
belongs_to :course
belongs_to :user
has_one :rating
# has fields :user_id, :course_id
end
class Rating
belongs_to :enrollment
belongs_to :course, through: :enrollment
belongs_to :user, through: :enrollment
end
When I try to create a Rating in the console, I get the following error:
User.first.ratings.create(text: "test", course_id: Course.first.id)
ArgumentError: Unknown key: through
Update
When I use has_one through insted, I get the following error:
ActiveRecord::HasManyThroughCantAssociateThroughHasOneOrManyReflection: Cannot modify association 'User#ratings' because the source reflection class 'Rating' is associated to 'Enrolment' via :has_one.
Is it possible to do it this way at all? Thanks!
class Course
has_many :users, through: :enrollments
has_many :enrollments
has_many :ratings, through: :enrollments
end
class User
has_many :courses, through: :enrollments
has_many :enrollments
has_many :ratings, through: :enrollments
end
class Enrollment
belongs_to :course
belongs_to :user
belongs_to :rating
# has fields :user_id, :course_id, rating_id
end
class Rating
has_one :enrollment
has_one :course, through: :enrollment
has_one :user, through: :enrollment
end
Note: Add foreignkey columns
And if you there is just one/two columns in ratings table merge them into enrollments like this.
class Course
has_many :users, through: :enrollments
has_many :enrollments
end
class User
has_many :courses, through: :enrollments
has_many :enrollments
end
class Enrollment
belongs_to :course
belongs_to :user
# has fields :user_id, :course_id, rating-columns...
end
Structure
Maybe you're complicating this too much
class Enrollment
belongs_to :course
belongs_to :user
end
This means you have a join model which stores unique records, referencing both course and user. Your ratings are on a per user and course basis?
Why don't you just include rating as an attribute of your enrolment model?:
#enrolments
id | user_id | course_id | rating | created_at | updated_at
If you give rating a numeric value (1 - 5), it will give you the ability to rate the different enrolments like this:
user = User.first
course = Course.first
user.enrolments.create(course: course, rating: 5)
--
Ratings
This is, of course, based on your current model structure.
If you want to include ratings for courses by users (not tied to enrolment), you may wish to use a join model called course_ratings or similar:
#app/models/user.rb
Class User < ActiveRecord::Base
has_many :enrolments
has_many :courses, through: :enrolments
has_many :ratings, through: :courses, class_name: "CourseRating"
end
#app/models/course.rb
Class Course < ActiveRecord::Base
has_many :enrolments
has_many :students, through: :enrolments, class_name: "User"
has_many :ratings, class_name: "CourseRating"
end
#app/models/course_rating.rb
Class CourseRating < ActiveRecord::Base
belongs_to :course
belongs_to :user
end
This will allow you to call:
user = User.first
user.courses.first.ratings

twitter model associations in rails

I am trying to build a twitter like data model in rails. This is what I have come up with.
class User < ActiveRecord::Base
has_many :microposts, :dependent => :destroy
end
class Micropost < ActiveRecord::Base
belongs_to :user
has_many :mentions
has_many :hashtags
end
class Mention< ActiveRecord::Base
belongs_to :micropost
end
class Hashtag < ActiveRecord::Base
belongs_to :micropost
end
Should I be using a has_many through association somewhere or is this accurate?
Edit: The final twitter MVC model.
class User < ActiveRecord::Base
has_many :microposts, :dependent => :destroy
userID
end
class Micropost < ActiveRecord::Base
belongs_to :user
has_many :link2mentions, :dependent => :destroy
has_many :mentions, through: :link2mentions
has_many :link2hashtags, :dependent => :destroy
has_many :hashtags, through: :link2hashtags
UserID
micropostID
content
end
class Link2mention < ActiveRecord::Base
belongs_to :micropost
belongs_to :mention
linkID
micropostID
mentionID
end
class Mention < ActiveRecord::Base
has_many :link2mentions, :dependent => :destroy
has_many :microposts, through: :link2mentions
mentionID
userID
end
Edit 2: A concise and accurate explanation
http://railscasts.com/episodes/382-tagging?view=asciicast
If two microposts use the same hashtag, you probably don't want to create two database records for that hashtag. In this case you would use has_many through:
class Hashtagging < ActiveRecord::Base
belongs_to :micropost
belongs_to :hashtag
end
class Hashtag < ActiveRecord::Base
has_many :hashtaggings
has_many :microposts, through: :hashtaggings
end
class Micropost < ActiveRecord::Base
...
has_many :hashtaggings
has_many :hashtags, through: :hashtaggings
end
When you create the Hashtagging migration, make sure it has the micropost_id and hashtag_id columns.

Resources