Hello, i'm new to rails. I have been fed up with active record associations. I did study associations from the rails guides. Yet i cant find myself a clear way to add associations to the models suggested in the diagram.
I have one doubt whether a single foreign key(SECOND MODEL) can reference two primary keys (SECOND MODEL LEVEL 2 FIRST & SECOND MODEL LEVEL 2 SECOND). This has been done because the user has to choose whether to add from the SECOND MODEL LEVEL 2 FIRST TABLE or the SECOND MODEL LEVEL 2 SECOND TABLE while inserting values into the SECOND MODEL.
If u find this hard to understand please leave a comment, ill make appropriate changes. And i would appreciate on how to query from the FINAL LEVEL FIRST with BASE-MODEL thorough a join condition.
You can use polymorphic association to refer to one table OR another, check the model below as per the posted image:
class BaseModel
has_many :first_models
has_many :second_models
end
class FirstModel
belgons_to :base_model
has_one :level_two_first_model
end
class LevelTwoFirstModel
belgons_to :first_model
end
class SecondModel
belgons_to :base_model
has_many :final_first_levels, as: :referenceable, :dependent => :destroy
has_many :final_second_levels, as: :referenceable, :dependent => :destroy
end
class LevelOneSecondModel
belongs_to :referenceable, polymorphic: true
has_many :final_first_levels
end
class LevelTwoSecondModel
belongs_to :referenceable, polymorphic: true
has_many :final_first_levels
end
class FinalFirstLevel
belongs_to :LevelOneSecondModel
end
class FinalSecondLevel
belongs_to :LevelTwoSecondModel
end
referenceable is used as the glue between the parent table and other polymorphic associations (LevelOneSecondModel OR LevelTwoSecondModel)
NB:
Don't forget to add the below line in the migration files of the 2 children tables used in polymorphic association.
t.references :referenceable, polymorphic: true, index: true
Reference:
http://guides.rubyonrails.org/association_basics.html#polymorphic-associations
Related
I have model course.rb with pre_courses is an array.
class Course < ActiveRecord::Base
serialize :pre_courses, Array
end
Now I want to check if an exist course is pre_course of any course by Activerecord or raw SQL (I am using MySQL), such as Course.where("pre_courses INCLUDEs self.id").
Is there any way to do this?
A serialized array is just a string in the db, so try using LIKE, for example:
Course.where("pre_courses LIKE ?", "% #{self.id}\n%")
Notice that a serialzed array adds a space before each item and a new line after, thus the added space before the interpolated string and the \n at the end.
It sounds like a pre_course is actually a regular course, a course can have many pre_courses and a pre_course can belong to many courses. A self referential has_many through relationship is possible and may give you more flexibility to work with your data than serializing it as an array.
You'll need a join model I'll call CoursePreCourse. It will have the columns course_id and pre_course_id. pre_course_id will be a foreign key for records on the courses table.
class CreateCoursePreCourses < ActiveRecord::Migration[5.1]
def change
create_table :course_pre_courses do |t|
t.references :course, foreign_key: true
t.references :pre_course, foreign_key: { to_table: :courses }
t.timestamps
end
end
end
class CoursePreCourse < ApplicationRecord
belongs_to :course
belongs_to :pre_course, class_name: 'Course'
end
class Course < ApplicationRecord
# A straight-forward has_many :through association for a course that has_many :pre_courses
has_many :course_pre_courses
has_many :pre_courses, through: :course_pre_courses
# A little coercion is necessary to set up the association as a pre_course that has_many :courses
has_many :pre_course_courses, class_name: 'CoursePreCourse', foreign_key: :pre_course_id
has_many :courses, through: :pre_course_courses
end
Now you can retrieve the courses that are pre_courses of any course with course.pre_courses. If you want to see if a course is a pre_course of other courses it's pre_course.courses. Similarly you can add a course to another course's pre_courses with either course.pre_courses << pre_course or pre_course.courses << course.
Do you ever say a word so many times it loses its meaning?
I am in my quest of overriding activerecord method, but I need to be access the table name many-to-many relationship :through . How do i do it?
For example I have model Student and Subject, to connect the two I use has_many Subjects, through: :registers.
I have a statement Student.find(1).subjects, how do i get the table name register from the activerecord statement?
Thanks
Student.rb
Class Student < ActiveRecord::Base
has_many :registers
has_many :subjects, :through => :registers
end
subject.rb
class Subject < ActiveRecord::Base
has_many :registers
has_many :students, :through => :registers
end
register.rb
Class Register
belongs_to :student
belongs_to :subjet
end
Make sure your associations added like this. And You can get your all subject lists by Student.find(1).subjects
And You can also check entries in Register table by using Register.all
You can access all the register records like below.
Register.all
From your statement "Student.find(1).subjects", if you wish to get the registers along with the subjects details, you can do as:
Student.find(1).subjects.select("subjects.name, registers.name")
I'm currently having trouble implementing a 1-to-2 association, which is polymorphic. I have three models involved in this, Rule, Ip and IpGroup. Each Rule has exactly two of Ipish, which can be either an Ip or IpGroup. However, when loading entries from DB, the ipish_from and ipish_to always remain nil. Also, don't get confused by class_name: "Ipish", there is no explicit class in the project named "Ipish"; in an older version of the project it was not polymorphic and it said class_name: "Ip".
class Rule
belongs_to :ipish_from, class_name: "Ipish", foreign_key: :ipish_id_from, polymorphic: true
belongs_to :ipish_to, class_name: "Ipish", foreign_key: :ipish_id_to, polymorphic: true
end
class Ip
has_and_belongs_to_many :ip_groups
has_many :rules_from, as: :ipish
has_many :rules_to, as: :ipish
end
class IpGroup
has_and_belongs_to_many :ips
has_many :rules_from, as: :ipish
has_many :rules_to, as: :ipish
end
The table in my MySQL-DB currently looks like this
++++++++++++++++++++++++++++
+ rules +
++++++++++++++++++++++++++++
+ ipish_id_from: int +
+ ipish_type_from: string +
+ ipish_id_to: int +
+ ipish_type_to: string +
++++++++++++++++++++++++++++
Any tips on how I should be doing this? I must use polymorphic associations for this. Also, this problem does only exist because of how the objects are related; I know how the "standard" polymorphism works. Maybe Rails expects a different column name to determine the Type of an Ipish object? I haven't found anything that says how to change what Rails expects, unfortunately.
In my rails application, I had to add a new column named is_leader for an association table.
The relationship for the association table is as follows:
has_and_belongs_to_many :analysis_responses, :join_table => "analysis_responses_participants"
Following is the code where the participant details have been saved to the db:
organization.people.create(participant)
the participant has got the following values
name: Test User
position:
birthdate:
id:
lead: "1"
If the lead value is 1, the is_leader column value should be 1 for the particular record.
I wanted to know how can I save the is_leader value in that association table in rails
Thanks
If you need to save attributes on the join table, then you will have to use a join model instead of a HABTM.
class Organization
has_many :analysis_responses
has_many :people, through: :analysis_responses
end
class AnalysisResponse
belongs_to :organization
belongs_to :person
end
class Person
has_many :analysis_responses
has_many :organizations, through: :analysis_reponses
end
I have a user friendship model that I want to write a lookup for
is a habtm relationship called peers, relating 2 users together. A relationship is a single connection (Joe <-> Steve, not Joe -> Steve and Steve -> Joe).
My join table is as follows:
user_id
peer_id
Both store a user id in the relationship. Below is the HABTM on the user.
has_and_belongs_to_many :peers, class_name: 'User',
foreign_key: 'user_id', association_foreign_key: 'peer_id',
join_table: 'users_peers'
I am trying to figure out the finder sql that will allow this record in the join table to show both sides.
user_id = steve.id
peer_id = joe.id
to show the relationships when I call joe.peers and steve.peers. Currently, steve.peers returns joe, but joe.peers shows nothing.
Generally relationships are best expressed as one way, or a pair of one-way relationships. This is because in most relational databases, it's easy to establish an A to B or B to A relationship, but not both with one record. You basically need two queries unless you make a lot of assumptions and hack around.
In my experience, using has_and_belongs_to_many isn't going to make your life easier as it's a relic from Rails 1.0 that isn't nearly as good as the has_many :through method that replaced it. In your case this is how that would play out:
class Node < ActiveRecord::Base
has_many :peers_of,
:class_name => 'Peer',
:foreign_key => :of_user_id
has_many :peers_to,
:class_name => 'Peer',
:foreign_key => :to_user_id
has_many :peers,
:through => :peers_of,
:source => :to_user
has_many :peers_with,
:through => :peers_to,
:source => :of_user
end
class Peer < ActiveRecord::Base
belongs_to :of_user,
:class_name => 'User'
belongs_to :to_user,
:class_name => 'User'
end
The semantics get a little messy, so you'll probably want to adjust them. The idea here is to establish a bi-directional relationship when adding a "peer", where that consists of a pair of A->B and B->A records.
For the purposes of querying you would only fetch, for instance, #user.peers and not have to worry about the peers_with inverse relationship as that should produce identical results if you've maintained data integrity.
You could just write the sql by hand:
class PeerRelation
belongs_to :user1, :class_name=>"User"
belongs_to :user2, :class_name=>"User"
end
class User
def set_peer(user)
user1_id, user2_id = [self.id, user.id].sort
PeerRelation.find_or_create_by_user1_id_and_user2_id(user1_id, user2_id)
end
def peers
User.joins("inner join peer_relations on
peer_relations.user1_id = #{self.id} or
peer_relations.user2_id = #{self.id}")
end
end
But tadman's approach is smarter from a data-integrity perspective, and is more in line with what a DBA would tell you. (see my comment to your question)