Multiple Foreign Keys with Ruby on Rails - mysql

I have the following setup:
One matchdays table with a column called home_team_id and one called visitor_team_id
and a team table.
My Match model looks like this:
class Match < ActiveRecord::Base
belongs_to :home_team, class_name: "Team", foreign_key: :home_team_id
belongs_to :visitor_team, class_name: "Team", foreign_key: :visitor_team_id
belongs_to :matchday
validates :home_team, presence: true
validates :visitor_team, presence: true
end
And the Team model like that:
class Team < ActiveRecord::Base
has_many :matches
has_many :player
end
Now it's getting tricky (at least for me). I'd like to be able to call team.matches and get all of the matches for the team. Since every team has home games and also games on the road.
Currently I'm getting a ActiveRecord::StatementInvalid Error because it's looking for the team_id column in the matches table.

So if I understand correctly, what you need is just a method that returns all games where the current team is playing. This should do the trick:
class Team < ActiveRecord::Base
has_many :player
def matches
Team.where(home_team_id => self.id, foreign_key => self.id)
# This line will also work if you want to try it out.
# Team.where("home_team_id = ?", self.id).where("foreign_key = ?", self.id)
end
end
Happy coding!

Related

How to write a deep join query for a filter in rails 6?

I'm trying to write a filter. I have an orders model that has multiple services and each service has one worker assigned to perform it.
I want to filter the order by the selected employee who performs any service in this order.
I'm trying to do #orders = Order.joins(:services).joins(:employees).where(services: {employees: {id: params[:employee_id]}}), I know that this is not correct. Please tell me how to make such a request.
order.rb
class Order < ApplicationRecord
has_many :order_services, dependent: :destroy
has_many :services, through: :order_services
end
order_service.rb
class OrderService < ApplicationRecord
belongs_to :order
belongs_to :service
belongs_to :employee
validates :order, presence: true
validates :service, presence: true
validates :employee, presence: true
end
service.rb
class Service < ApplicationRecord
has_many :order_services, dependent: :destroy
has_many :orders, through: :order_services
belongs_to :employee, optional: true
end
employee.rb
class Employee < ApplicationRecord
has_many :order_services
has_many :services, through: :order_services
end
I want to note that my order_service model is a connecting model for the service and for the employee. In theory, the connection of the order and the service can only be in the presence of a worker. + an additional question is whether such interaction is not a bad practice, or it would be better to divide them into order_service and service_employee? Thanks.
It was a mistake to try to get to the employee through the service, because access to it is much closer. We do not need to call an employee through the service, because this employee is recorded in the order_service table, since by condition we have an order and service connection in the presence of an employee, therefore we can not take service into account at all.
Order.joins(:order_services).where(order_services: {employee_id: params[:employee_id]})
I think this is what you are asking for.
#orders = Order.joins(:order_services).where(order_services: { employee_id: params[:employee_id] }).distinct

Activerecord "where" condition for Array attribute

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?

How to sort nested items on field in 'parent' model?

I am new to Ruby on Rails and try to make the right query. But after reading the documentation and examples I don't manage to get the right query out of it. So I hope someone can point me in the right direction.
Situation I build an app where trainers can setup trainings, and give these trainings on several dates (the dates are called thrills), other users can subscribe for these thrills. It has the following structure:
class User
has_many :trainings
has_many :thrills, through: :trainings
has_many :reservations
class Training
belongs_to :user
has_many :reservations
has_many :thrills
has_many :users, through: :thrills
class Thrill
belongs_to :training
has_many :reservations
has_many :users, through: :reservations
class Reservation
belongs_to :user
belongs_to :thrill
has_one :training, through: :thrill
Question
How can I make a list of all reservations of the current_user ordered by the thrilldate? The thrilldate is set in the Thrills model.
In my reservations_controller.rb I have:
#reservations = current_user.reservations
This gives the right list of all the reserations, but I want to sort list this on reservation.thrill.thrilldate
I tried so by using this view:
<% #reservations.order("reservation.thrill.thrilldate ASC").each do |reservation| %>
Unfortunately this gives the error:
SQLite3::SQLException: no such column: reservation..thrill.thrilldate: SELECT
"reservations".* FROM "reservations" WHERE "reservations"."user_id" =
? ORDER BY reservation.thrill.thrilldate ASC
Who knows how I can refer to the thrilldate in the Thrills model? Thanks for helping me out!
Assuming thrilldate is a column on Thrill
#reservations = current_user.reservations.joins(:thrill).order('thrills.thrilldate asc')

Query in Ruby on Rails 4 to make a selection based on the current user

I am new to Ruby on Rails and try to make the right query. But after reading the documentation and examples I don't manage to get the right query out of it. So I hope someone can point me in the right direction.
Situation
I build an app where trainers can setup trainings, and give these trainings on several dates (the dates are called thrills), other users can subscribe for these thrills. It has the following structure: models and needed table.
My models code looks like this:
class User
has_many :trainings
has_many :thrills, through: :reservations
has_many :reservations
class Training
belongs_to :user
has_many :reservations
has_many :thrills
has_many :users, through: :thrills
class Thrill
belongs_to :training
has_many :reservations
has_many :users, through: :reservations
class Reservation
belongs_to :user
belongs_to :thrill
has_one :training, through: :thrill
On an index page I want to show all the thrills that the current user has setup sorted by date. I think I need a query that comes up with the table in the uploaded image, and from that table I can select all Thrills where current_user.id = user_id
On the search page I want to show only the trainings that have a Thrill that is not full (therefore I want to make a count of the Reservations)
I was thinking of something like this:
#thrills = Thrill.joins(:trainings).where('? = trainings.user_id, current_user.id')
or
#thrills = Thrill.where('? = #thrill.training.user_id', current_user.id).all
or
#thrills = Thrill.joins(:trainings).where(trainings: { user_id: current_user.id })
But unfortunately none of them works. Does someone have an idea how to solve this? Thanks in advance!
Usually you have these two models:
class Thrill < ActiveRecord::Base
belongs_to :user
end
class User < ActiveRecord::Base
has_many :thrills
end
So for your index page what you can do is:
current_user.thrills # => ActiveRecord::Relation (can call each, map etc.)

Creating nested records on create with Rails

I have a projects model that I am using to auto generate departments within a specific project on create. This is included in the projects model with:
class Project < ActiveRecord::Base
attr_accessible :title, :departments_attributes, :positions_attributes, :id
belongs_to :user
has_many :departments
has_many :positions
validates :title, presence: true
before_create :set_departments
accepts_nested_attributes_for :departments
accepts_nested_attributes_for :positions
private
def set_departments
self.departments.build department: "Test Dept", production_id: self.id
end
end
Each department has many positions. I am trying to create positions as well for the departments. How could I associate a new position with a department in this model?
There are two ways:
#app/models/project.rb
class Project < ActiveRecord::Base
has_many :departments
accepts_nested_attributes_for :departments
before_create :set_department
private
def set_department
self.departments.build department: "Test"
end
end
#app/models/department.rb
class Department < ActiveRecord::Base
has_many :positions
accepts_nested_attributes_for :positions
before_create :set_positions
private
def set_positions
self.positions.build x: y
end
end
... or ...
#app/models/project.rb
class Project < ActiveRecord::Base
has_many :departments
accepts_nested_attributes_for :departments, :projects
before_create :set_departments
private
def set_departments
dpt = self.departments.build department: "Test"
dpt.positions << Position.new position: "Admin"
dpt.positions << Position.new position: "Tester"
end
end
--
You can also declare multiple nested attributes on a single line:
accepts_nested_attributes_for :departments, :positions
If I understand your question correctly, you might do something like this in your Department model:
after_create { self.positions.create! }
Though this might be a problematic approach. Creating records like this using ActiveRecord callbacks (which is what gives us after_create) can make your whole app really fragile. For example, if you do this, you'll never be able to make a department without an associated position. Perhaps one day you'll need to do just that.
So even though it's not the exact answer to your question, I suggest looking at created these associated models in a service object, or at least in controller code.
You can add a new position with:
Project.first.positions << Position.create(:foo => 'foo', :bar => 'bar')
or
position = Position.create(:foo => 'foo', :bar => 'bar')
Department.first.positions << position
Project.first.positions << position
Obviously the ".first" is just for illustration and you can use the << notation with any Department or Project instance.
Looking at this again, it seems like a really good fit for polymorphic associations.
class Position < ActiveRecord::Base
belongs_to :positioned, polymorphic: true
end
class Project < ActiveRecord::Base
has_many :positions, as: :positioned
end
class Department < ActiveRecord::Base
has_many :positions, as: :positioned
end
And in your migration:
create_table :positions do |t|
...
t.integer :positioned_id
t.string :positioned_type
...
end
There may be a more suitable way to name things for your app but this is the general idea.