How can I create a join without sql code in rails? - ruby-on-rails

I can't make a join in rails, I don't know what is wrong here. my classes are:
class Serie < ActiveRecord::Base
has_many :user_serie
has_many :user, :through => :user_serie
end
class UserSerie < ActiveRecord::Base
belongs_to :serie
belongs_to :user
end
and
class User < ActiveRecord::Base
has_many :user_serie
has_many :serie, :through => :user_serie
end
and the select is:
#series = Serie.all :joins => :user
so the generated select is:
SELECT "series".* FROM "series"
INNER JOIN "user_series" ON "series"."id" = "user_series"."serie_id"
INNER JOIN "users"
ON 0
AND "users"
AND 'id'
AND "users"."id"
AND 0
AND "user_series"
AND 'user_id'
AND "user_series"."user_id"
AND "users"."id" = "user_series"."user_id"
What can I do to make this select works?
I've tried to make the has_many with plural, but then I have this error:
uninitialized constant Serie::UserSeries

You have wrong relations, should be:
class Serie < ActiveRecord::Base
has_many :user_series
has_many :users, :through => :user_series
end
class UserSerie < ActiveRecord::Base
belongs_to :serie
belongs_to :user
end
class User < ActiveRecord::Base
has_many :user_series
has_many :series, :through => :user_series
end
When you get exception with uninitialized class, then use explicit :class_name like below:
class Serie < ActiveRecord::Base
has_many :user_series, :class_name => "UserSerie"
# or "::UserSerie", i'm not 100% sure which one, rather just as I wrote
has_many :users, :through => :user_series
end

Related

Rails has_many :through scoped with joins

I'm trying to create a has_many :through association with a custom scope. The problem is that the scope has a joins with a 3rd model, and that seems to be breaking the association.
These are the models:
class Student < ApplicationRecord
has_many :lesson_applications, through: :lesson_requests
has_many :lessons, through: :lesson_applications
has_many :scoped_lessons, -> { custom_scope }, through: :lesson_applications, source: :lesson
has_many :tutors, through: :scoped_lessons # Broken association
end
class Lesson < ApplicationRecord
belongs_to :lesson_application
has_one :tutor, through: :lesson_application
has_one :time_range, as: :time_rangeable
scope :custom_scope, (lambda {
joins(:time_range).where('time_ranges.attribute BETWEEN ? AND ?', value1, value2)
})
end
class LessonApplication < ApplicationRecord
belongs_to :lesson_request
belongs_to :tutor
has_one :lesson
end
class Tutor < ApplicationRecord
has_many :lesson_applications
has_many :lessons, through: lesson_applications
end
class TimeRange < ApplicationRecord
belongs_to :time_rangeable, polymorphic: true
end
I expected to get the student's tutors from the scoped lessons, but instead I get an missing FROM-clause entry for table 'time_ranges'. Which is clearly and error that can be seen on the generated query.
The generated query when I do student.tutors is:
SELECT "tutors".* FROM "tutors" INNER JOIN "lesson_applications" ON "tutors"."id" = "lesson_applications"."tutor_id" INNER JOIN "lessons" ON "lesson_applications"."id" = "lessons"."lesson_application_id" INNER JOIN "lesson_applications" "lesson_applications_tutors" ON "lessons"."lesson_application_id" = "lesson_applications_tutors"."id" INNER JOIN "lesson_requests" ON "lesson_applications_tutors"."lesson_request_id" = "lesson_requests"."id" WHERE "lesson_requests"."student_id" = $1 AND (time_ranges.start BETWEEN '2018-04-11 20:27:34.798992' AND '2018-04-11 20:27:34.799090') LIMIT $2
The method I'm using temporarily instead of the association is:
class Student < ApplicationRecord
def tutors
scoped_lessons.map(&:tutor).uniq
end
end
I am using ruby 2.5.1 with Rails 5.1.6
Thank you in advance.
Edit: some associations were wrong.

Rails multiple joins AR query and where clause

I have the following models:
class Product < ActiveRecord::Base
has_many :product_recommendation_sets, :dependent => :destroy
has_many :recommendation_sets, :through => :product_recommendation_sets
end
class ProductRecommendationSet < ActiveRecord::Base
belongs_to :product
belongs_to :recommendation_set
end
class RecommendationSet < ActiveRecord::Base
has_many :product_recommendation_sets, :dependent => :destroy
has_many :products, :through => :product_recommendation_sets
has_many :recommendation_recommendation_sets, :dependent => :destroy
has_many :recommendations, :through => :recommendation_recommendation_sets
end
class RecommendationRecommendationSet < ActiveRecord::Base
belongs_to :recommendation
belongs_to :recommendation_set
end
class Recommendation < ActiveRecord::Base
has_many :recommendation_recommendation_sets, :dependent => :destroy
has_many :recommendations, :through => :recommendation_recommendation_sets
end
Im trying to select all recommendations where product_id = x, by doing:
RecommendationSet.joins(:products, :recommendations).where(product_id:1)
However I get an unknown column error. How can I join select all recommendations by a given product_id.
Psudo code:
Find recommendation_sets where product_id = ?. Find recommendations where recommendation_set_id = ?.
You were pretty close, in your case this should work:
RecommendationSet.joins(:products, :recommendations).where(products: { id: 1 })
Remember that in the where clause you have to use the table's name in the conditons hash, not the relation's name.
As an Example, consider these relations:
User belongs_to :group
Group has_many :users
Notice the syntax (plural / singular):
User.joins(:group).where(groups: { name: 'Admin' })
# ^ ^
Group.joins(:users).where(users: { id: 15 })
# ^ ^

Joining one table two times

My db schema:
tournaments(id, ...)
teams(tournament_id, id, ...)
matches(tournament_id, id, team_id_home, team_id_away, ...)
Models:
class Tournament < ActiveRecord::Base
has_many :teams, dependent: :destroy
has_many :matches, dependent: :destroy
...
end
class Team < ActiveRecord::Base
belongs_to :tournament
...
end
class Match < ActiveRecord::Base
belongs_to :tournament
has_many :teams
...
end
I would like to have the following data in my view:
match_id team_id_home team_id_away team_id_home_name team_id_away_name
So, I'm asking for help with the following query (I'm trying to get team's names, but having problem with joining):
#matches = #tournament.matches.where(:tournament => #tournament).joins(:teams).paginate(page: params[:page])
I'm fairly new to rails, but you should be able to setup your associations like this: (going from memory)
class Match < ActiveRecord::Base
belongs_to :tournament
has_one :home_team, :class_name => "Team", :foreign_key => "team_id_home"
has_one :away_team, :class_name => "Team", :foreign_key => "team_id_away"
end
#####
m = Match.first
m.away_team.team_name
m.home_tam.team_name
Or in your case:
#matches = #tournament.matches.paginate(page: params[:page])
I don't think you need the where function: the has_many association tells rails to only pull matching matches.
It is belongs_to, not has_one in Match model.
class Match < ActiveRecord::Base
belongs_to :tournament
belongs_to :home_team, :class_name => "Team", :foreign_key => "team_id_home"
belongs_to :away_team, :class_name => "Team", :foreign_key => "team_id_away"
end
class Team < ActiveRecord::Base
belongs_to :tournament
has_many :matches
end
Now I can use tournament.home_team.name in my view

Rails 4 Has_many :through join association with select

I am trying to upgrade a rails 3.0 app to rails 4.0. One of the behaviour I noticed is the relationship between the models stopped working.
Assume we have the following models:
class Student < ActiveRecord::Base
has_many :teacher_students
has_many :teachers, :through => :teacher_students, :select => 'teacher_students.met_with_parent, teachers.*'
# The Rails 4 syntax
has_many :teachers, -> { select('teacher_students.met_with_parent, teachers.*') }, :through => :teacher_students
end
class Teacher < ActiveRecord::Base
has_many :teacher_students
has_many :students, :through => :teacher_students, :select => 'teacher_students.met_with_parent, students.*'
end
class TeacherStudent < ActiveRecord::Base
belongs_to :teacher
belongs_to :student
# Boolean column called 'met_with_parent'
end
Now we are able to do:
teacher = Teacher.first
students = teacher.students
students.each do |student|
student.met_with_parent # Accessing this column which is part of the join table
end
This worked for Rails 3.0, but now on Rails 4.0 I am getting Unknown column 'met_with_parent' in 'field list' I believe Rails 4 is trying to be smart and not loading the entire given join tables.
I personally would recommend the following approach, using scopes:
class Student < ActiveRecord::Base
has_many :teacher_students
has_many :teachers, :through => :teacher_students
end
class Teacher < ActiveRecord::Base
has_many :teacher_students
has_many :students, :through => :teacher_students
scope :met_with_parent, -> { joins(:teacher_students).where('teacher_students.met_with_student = ?', true) }
end
class TeacherStudent < ActiveRecord::Base
belongs_to :teacher
belongs_to :student
end
Then you can do the following:
Teacher.first.students.met_with_parent
This allows you to maintain the relationships AND filter when needed.

Trouble update has_many :through record

I am having an issue updating a has_many through record. Here is my setup:
class TastingGroup < ActiveRecord::Base
has_many :group_wine
has_many :wines, through: :group_wine
end
class GroupWine < ActiveRecord::Base
belongs_to :tasting_group
belongs_to :wine
end
class Wine < ActiveRecord::Base
has_many :group_wine
has_many :tasting_groups, through: :group_wine
end
I was trying to use the acts_as_list for this, because the order of the wines in a TastinGroup matter, so I have added a 'position' attribute to the GroupWine model.
However, when I try to even update a GroupWine record, I get the following error, and here is what I am doing.
gw = GroupWine.first
#<GroupWine:0x007fd9f7c38b50> {
:wine_id => 1,
:tasting_group_id => 1,
:position => nil
}
gw.position = 1
gw.save
And here is the error I get...
ActiveRecord::StatementInvalid: Mysql2::Error: Unknown column 'group_wines.' in 'where clause': UPDATE `group_wines` SET `position` = 3 WHERE `group_wines`.`` IS NULL
What is up with the NULL for group_wines, and why is it adding that where clause?
Thanks.
Try pluralizing the group_wine object to group_wines
class TastingGroup < ActiveRecord::Base
has_many :group_wines
has_many :wines, through: :group_wines
end
class GroupWine < ActiveRecord::Base
belongs_to :tasting_group
belongs_to :wine
end
class Wine < ActiveRecord::Base
has_many :group_wines
has_many :tasting_groups, through: :group_wines
end

Resources