I have three tables in rails
This are the Tables
Employee = (no association at all)
User = has many attendance
Attendance = belongs to user
then my question is how can i query the three table with this.
User table joins Attendance then also joins Employee where employee.code = users.Empkey
how can i translate it to join the three tables in one queries with rails 5
You should create ActiveRecord associations between employees and users.
class Employee < ApplicationRecord
belongs_to :user, foreign_key: "code", class_name: "User"
end
class User < ApplicationRecord
has_many :attendances
has_one :employee, foreign_key: "Empkey", class_name: "Employee"
end
class Attendance < ApplicationRecord
belongs_to :user
end
Now you can play around as you like.
employee = Employee.first
#employee_attendances = employee.user.attendances
You can use raw sql in join table to join 3 tables like see in example
User.joins(:attendances).joins("Inner joins employees on employees.code = users.Empkey")
Hope this will help
Related
I'm working on an existing app which has the structure (simplified and) described below. One of our new queries is to find all activity in a company which is rather complicated and non-performant to build. It seems hard to write the query in ActiveRecord, so, I'm trying to use Scenic and build a Materialized View since this query is going to be mostly read-only.
So, we have Person, Group, Project, Report, Update and ActivityReceipt along with some join models. A person belongs to various groups and various projects.
My goal is to get show a feed of group activity of all of groups that a member is part of, so I'm looking to performantly fetch Activity by group, along with the author information, sorted by time and it seems like a materialized view with the following columns would make that happen:
activity_receipt_id, group_id, person_id
class Person < ApplicationRecord
has_many :groups
has_many :projects
end
class Membership < ApplicationRecord
# id, group_id, person_id
belongs_to :group
belongs_to :person
end
class Company < ApplicationRecord
has_many :projects
has_many :people
end
class GroupDonation < ApplicationRecord
# id, group_id, project_id
belongs_to :group
belongs_to :project_id
end
class Project < ApplicationRecord
has_many :group_donations
has_many :people
end
class ActivityReceipt < ApplicationRecord
# polymorphic belongs_to relation to 'postable' which are reports, & updates
# so, it has id, postable_id, and postable_type as columns and then other specific metadata
belongs_to :postable
end
class Report < ApplicationRecord
# project_id, membership_id and other specific metadata
belongs_to :project
belongs_to :membership #to track the author
has_one :activity_receipt
end
class Update < ApplicationRecord
# project_id, membership_id and other specific metadata
belongs_to :project
belongs_to :membership #to track the author
has_one :activity_receipt
end
Conceptually, the query is for all the given group_ids, fetch the associated projects and then their associated reports & updates, and then their activity receipts which is eventually needed. I'm not very familiar with writing SQL to generate a view so I have been struggling on how to make such a materialized view with polymorphic relations, and if it is even possible / recommended
Here is what I have so far:
SELECT groups.id AS group_id, people.id AS people_id, activity_receipts.id as activity_receipt_id
FROM groups
JOIN group_donations ON group_donations.group_id = groups.id
JOIN projects ON projects.id = group_donations.group_id
JOIN reports ON reports.project_id = project.id
JOIN updates ON updates.project_id = project.id
JOIN activity_receipts ON
// Stuck here
I am trying to order my active record query by a specific table column but with the standard Query.order(:id) format rails thinks the column is in a different table.
This is my active record query:
#course = Course.select('*').joins(:course_metadata, :courseContent).where(course_id: params[:id]).order(:content_order)
Here are my models:
class Course < ActiveRecord::Base
has_one :course_metadata
has_many :xrefCourseContent, foreign_key: 'course_id'
has_many :courseContent, through: :xrefCourseContent, foreign_key: 'course_guid'
end
class CourseMetadata < ActiveRecord::Base
self.table_name = 'course_metadata'
belongs_to :course
end
class CourseContent < ActiveRecord::Base
self.table_name = 'courseContent'
has_many :xrefCourseContent, foreign_key: 'content_id', primary_key: 'content_id'
has_many :course, through: :xrefCourseContent, foreign_key: 'content_id',
end
class XrefCourseContent < ActiveRecord::Base
self.table_name = 'xrefCourseContent'
belongs_to :course, primary_key: 'course_id', foreign_key: 'course_guid'
belongs_to :courseContent, primary_key: 'content_id', foreign_key: 'content_guid'
end
The query connects courses to course content through the xref table.
SELECT * FROM [courses]
INNER JOIN [course_metadata] ON [course_metadata].[course_id] = [courses].[course_id]
INNER JOIN [xrefCourseContent] ON [xrefCourseContent].[course_id] = [courses].[course_id]
INNER JOIN [courseContent] ON [courseContent].[content_id] = [xrefCourseContent].[content_id]
WHERE [courses].[course_id] = #0
ORDER BY [courses].[content_order]
This is the sql query that shows up in the error message and as you can see, it thinks the content_order column is in the courses table when in fact it is in the xrefCourseContent table.
I'm new to rails and am still trying to wrap my mind around the whole Active Record system so forgive me if some of the code in my models is redundant or unnecessary, but feel free to point out anything that could be improved.
It should be
#course = Course.select('*').joins(:course_metadata, :courseContent)
.where(course_id: params[:id])
.order("xrefCourseContents.content_order")
You need to specify the table from which you will find the content_order column.
I have two tables named books (id, name, author_name) and users (id, name, location). A book can either be viewed by a user or edited by a user. So, for these two relationships I have two join tables viz. book_editor_users (book_id, user_id) and book_viewer_users (book_id, user_id).
How do I model this in Rails such that I can retrieve editor users and viewer users like this:
Book.find(1).book_editor_users
Book.find(1).book_viewer_users
My attempt for the book and user model are:
class Book < ActiveRecord::Bas
has_many :book_editor_users
has_many :users, through: :book_editor_users
has_many :book_viewer_users
has_many :users, through: :book_viewer_users # I am confused on how to setup this line
end
class User < ActiveRecord::Base
has_many :books, through: :book_editor_users
has_many :books, through: :book_viewer_users # I am confused here too
end
Join models I have written are:
class BookEditorUser < ActiveRecord::Base
belongs_to :book
belongs_to :user
end
class BookViewerUser < ActiveRecord::Base
belongs_to :book
belongs_to :user
end
There is another work around that I thought of, but I am not sure whether it is the Rails way. That work around is to have a single join table book_users (book_id, user_id, type) where the type column can capture whether it is an editor relationship or a viewer relationship.
Single joining table(books_users) is the best way for doing this with permission column in it. Lets say integer column with 1 for view 2 for edit(3 for both if it could be a possibilty). And to get editor or viewer users you should write scope in their joining model(BooksUsers)
scope :viewers, -> { where(permission: 1) }
scope :editors, -> { where(permission: 2) }
now you can find books particular user from these scope
Book.find(1).books_users.viewers
Book.find(1).books_users.editors
I've got the an has_one association:
has_one association user -> customer models
will the user have the customer_id or customer will have the user_id attribute?
other question: into my _form i'd like to have a select/option with all the users that hasn't associated with a customer which is the best way to do that?
thanks a lot.
The _id field is always in the model with the belongs_to, and refers to the other table name.
class Customer < ActiveRecord::Base
belongs_to :user
end
class User < ActiveRecord::Base
has_one :customer
end
In this case, the customers table will have a user_id field.
For the second question, missing values are found in SQL using outer joins.
The SQL you want would be
select
from users
left outer join customers on users.id = customers.user_id
where customers.id is null
In ActiveRecord, add a scope to your User class.
In Rails 3.x:
class User < ActiveRecord::Base
has_one :customer
scope :missing_customer,
includes(:customer).where("customers.id is null")
end
In Rails 2.3.x:
class User < ActiveRecord::Base
named_scope :missing_customer,
{ :joins => "left outer join customers on users.id = customers.user_id",
:conditions => "customers.id is null" }
end
When one table has 2 columns which refer same master table with ActiveRecord on Rails3
There are tables like below.
Depts
id
dept_name
Users
id
dept_id
previous_dept_id
Users table has two columns which refer Depts table.
How can I get dept_name for each columns?
class Dept < ActiveRecord::Base
has_many :user
end
class User < ActiveRecord::Base
belongs_to :dept
end
I think what you're looking for is the following:
class User < ActiveRecord::Base
belongs_to :dept
belongs_to :previous_dept, :class_name => 'Dept', :foreign_key => 'previous_dept_id'
end
You should then be able to access the two departments like this:
dept_name = user.dept.dept_name
previous_dept_name = user.previous_dept.dept_name
It's important to note that your Dept model will only find users by the dept_id column. I think you'd have to add a second has_many to Dept if you needed to find users by their previous dept. Something like:
class Dept < ActiveRecord::Base
has_many :user
has_many :previous_user, :class_name => 'User', :foreign_key => 'previous_dept_id'
end