I have the following models:
class Business < ApplicationRecord
has_many :shopping_trips
end
class ShoppingTrip < ApplicationRecord
belongs_to :business
has_many :purchases
end
class Purchase < ApplicationRecord
belongs_to :shopping_trip
end
So a Business can have many shopping trips, and each of these shopping trips can have many purchases.
I am trying to run a simple query on the Purchase table to find purchases that belong to a particular business. So I'm writing this:
purchases = Purchase.joins(:shopping_trip => :business ).where(:shopping_trip => {:business_id => 1})
Unfortunately it's not working. I get the following error:
ActiveRecord::StatementInvalid: PG::UndefinedTable: ERROR: missing FROM-clause entry for table "shopping_trip"
LINE 1: ...sses"."id" = "shopping_trips"."business_id" WHERE "shopping_...
^
: SELECT "purchases".* FROM "purchases" INNER JOIN "shopping_trips" ON "shopping_trips"."id" = "purchases"."shopping_trip_id" INNER JOIN "businesses" ON "businesses"."id" = "shopping_trips"."business_id" WHERE "shopping_trip"."business_id" = $1
The join looks about right but the where clause seems to fail.
ActiveRecord::StatementInvalid: PG::UndefinedTable: ERROR: missing
FROM-clause entry for table "shopping_trip"
You need to specify table name not the association name inside the where. So shopping_trip should be shopping_trips
purchases = Purchase.joins(:shopping_trip => :business ).where(:shopping_trips => {:business_id => 1})
A better solution is to set up indirect associations so that you can query through the join model without manually joining:
class Business < ApplicationRecord
has_many :shopping_trips
has_many :purchases, through: :shopping_trips
end
class ShoppingTrip < ApplicationRecord
belongs_to :business
has_many :purchases
end
class Purchase < ApplicationRecord
belongs_to :shopping_trip
has_one :business, through: :shopping_trip
end
You can now query from either side:
#business = Business.eager_load(:purchases).find(1)
#purchases = #business.purchases
# or
#purchases = Purchase.eager_load(:buisness).where(businesses: { id: 1 })
Check This...
all_purchase = Purchase.all
all_purchase.each do |each_purchase|
each_purchase.shopping_trip.business
end
Related
I have model with polymorhphic reference to two other models. I've also included distinct references per this article eager load polymorphic so I can still do model-specific queries as part of my .where clause. My queries work so I can search for scores doing Score.where(athlete: {foo}), however, when I try to do a .create, I get an error because the distinct reference alias seems to be blinding Rails of my polymorphic reference during validation.
Given that athletes can compete individually and as part of a team:
class Athlete < ApplicationRecord
has_many :scores, as: :scoreable, dependent: :destroy
end
class Team < ApplicationRecord
has_many :scores, as: :scoreable, dependent: :destroy
end
class Score < ApplicationRecord
belongs_to :scoreable, polymorphic: true
belongs_to :athlete, -> { where(scores: {scoreable_type: 'Athlete'}) }, foreign_key: 'scoreable_id'
belongs_to :team, -> { where(scores: {scoreable_type: 'Team'}) }, foreign_key: 'scoreable_id'
def athlete
return unless scoreable_type == "Athlete"
super
end
def team
return unless scoreable_type == "Team"
super
end
end
When I try to do:
Athlete.first.scores.create(score: 5)
...or...
Score.create(score: 5, scoreable_id: Athlete.first.id, scoreable_type: "Athlete")
I get the error:
ActiveRecord::StatementInvalid (SQLite3::SQLException: no such column: scores.scoreable_type
Thanks!
#blazpie, using your scoping suggestion worked for me.
"those scoped belongs_to can be easily substituted by scopes in Score: scope :for_teams, -> { where(scorable_type: 'Team') }
I have a model with this relationship:
class Plan < ApplicationRecord
has_many :enrollment_plans
has_many :enrollments, through: :enrollment_plans
...
end
EDIT Here is the join table:
class EnrollmentPlan < ApplicationRecord
belongs_to :enrollment, required: true
belongs_to :plan, required: true
end
I tried to throw this scope on the model:
scope :for_enrollment, -> (enrollment) { where('enrollments.enrollment_id = ?', enrollment.id) }
but I get the following error. I am trying to figure out why I can't do this query. What do I need to change it to?
pry(main)> Plan.for_enrollment(Enrollment.last).to_a
ActiveRecord::StatementInvalid: PG::UndefinedTable: ERROR: missing FROM-clause entry for table "enrollments"
LINE 1: SELECT "plans".* FROM "plans" WHERE (enrollments.enrollment_...
^
ActiveRecord does not include associations by default, you need to add enrollments to query by hand. Try:
scope :for_enrollment, -> (enrollment) do
joins(:enrollments).
where('enrollments.id = ?', enrollment.id)
end
This scope will make query with joins of three tables: plans, enrollment_plans and enrollments. You may do the same logic with two tables query:
scope :for_enrollment, -> (enrollment) do
joins(:enrollment_plans).
where('enrollment_plans.enrollment_id = ?', enrollment.id)
end
I stucked and I don't know how to write correct query in RoR to achieve active record.
Relations between tables:
imed_patient has one imed_operator
imed_operator has many imed_operator_contacts
imed_patient has_many imed_operator_conatc through imed_operator
Definition of models :
class ImedOperator < ActiveRecord::Base
self.table_name = "imed_operator"
self.primary_key = "code"
has_one :imed_patient, foreign_key: 'r_opr_code'
has_many :imed_operator_contact, :foreign_key => "r_opr_code"
end
class ImedOperatorContact < ActiveRecord::Base
self.table_name = "imed_operator_contact"
end
class ImedPatient < ActiveRecord::Base
self.table_name = "imed_patient"
self.primary_key = "code"
has_many :visit, :foreign_key => "r_ptn_code"
belongs_to :imed_operator , foreign_key: 'r_opr_code'
has_many :imed_operator_contact, through: :imed_operator
end
Good SQL in PostgreSQL:
select * from imed_patient
INNER JOIN imed_operator ON imed_patient.r_opr_code = imed_operator.code
INNER JOIN imed_operator_contact ON imed_operator.code = imed_operator_contact.r_opr_code
where (imed_operator_contact.r_ct_id = 1 or imed_operator_contact.r_ct_id = 2) and imed_operator_contact.value = '501'
Code now (not working) is:
#pacjenci = ImedPatient.ImedOperatorContact.where('imed_operator_contact.r_ct_id = ? or imed_operator_contact.r_ct_id = ? and imed_operator_contact.value = ?',1,2,'+48501')
Error during run:
NoMethodError in PacjenciController#szukajpacjenttel undefined method
`ImedOperatorContact' for #
Anybody can help me ?
SOLVED
Thanks guys for inspiration. I solved it by:
#pacjenci = ImedPatient.joins(:imed_operator).joins(:imed_operator_contact).where('imed_operator_contact.value' => '+48501', 'imed_operator_contact.r_ct_id' => [1,2])
I used information from here point 12.1.3.2 Joining Nested Associations (Multiple Level)
Special Thanks to Andy
Try adding this to your ImedPatient:
has_many :imed_operator_contacts, through: :imed_operator
With that you should be able to use any ActiveRecord/arel style query:
imed_patient.imed_operator_contacts.where(value: '501')
the structure of my app is as follows:
c
lass Project < ActiveRecord::Base
has_and_belongs_to_many :team_members
has_one :legal_contract
has_many :documents
end
class ProjectsTeamMember < ActiveRecord::Base
belongs_to :project
belongs_to :team_member
end
class LegalContract < ActiveRecord::Base
belongs_to :project
end
class TeamMember < ActiveRecord::Base
has_many :projects_team_members
has_many :projects, through: :projects_team_members
has_and_belongs_to_many :projects
end
I am trying to find all team_members who are associated with legal_contract with one of ids from an array. Trying the includes method:
team_members = TeamMember.includes( {projects_team_members: [ { project: :legal_contract} ] } )
I wonder now how do I narrow it down now to pull only those tmembers and not all. I tried
arry= [1,3,5]
team_members = TeamMember.includes( {projects_team_members: [ { project: :legal_contract} ] }).where('legal_contract.id IN', arry)
but getting an error
ActiveRecord::StatementInvalid: PG::SyntaxError: ERROR: zero-length delimited identifier at or near """"
LINE 1: ...s"."updated_at" AS t0_r6, "projects_team_members"."" AS t1_r...
Does anyone know? Thanks
**UPDATE**
Thanks to Karlingen
TeamMember.joins(:projects => :legal_contract).where(legal_contracts: { id: [1,3,5] })
You need to accomplish this through a join like so:
TeamMember.joins(:projects => :legal_contract).where(legal_contracts: { id: [1,3,5] })
First you join the projects table and its legal contract. And then you search for all legal contracts that has the given ids.
Do note that the key in the Where clause is written in plural since it is the name of the table.
You need to set a primary key for projects_team_members, are you sure you have one?
It appears as though Rails is creating invalid syntax when trying to find a projects_team_members:
"projects_team_members".""
I am trying to use update_all through an association, and i am getting mysql errors, anyone know why please?
class Basket < ActiveRecord::Base
has_many :basket_items
has_many :articles, :through => :basket_items
def activate_articles
articles.update_all :active => true
end
end
class BasketItem < ActiveRecord::Base
belongs_to :basket
belongs_to :item
belongs_to :article
end
Mysql::Error: Unknown column 'basket_items.basket_id' in 'where clause': UPDATE `articles` SET `active` = 1 WHERE ((`basket_items`.basket_id = 114))
http://dev.rubyonrails.org/ticket/5353
Looks like there was a problem with n-n associations using has_many :through and using update all. Nothing seems to have been done.
1-n associations do appear to work.
Bug?
dev.rubyonrails moved it's tickets to github's issue tracker. Here is the moved link: https://github.com/rails/rails/issues/522
#nolman posted this help on the ticket
#daicoden and I at #square were pairing on this and we were able to put something together along the lines of:
class Comment
class << self
def trash_all
sql = "UPDATE #{quoted_table_name} "
add_joins!(sql, {})
sql << "SET #{sanitize_sql_for_assignment({:trashed => true})} "
add_conditions!(sql, {})
connection.execute(sql)
end
end
end
Now you can call todolist.comments(:conditions => {:trashed => false}).trash_all
This results in the following SQL:
UPDATE `comments` INNER JOIN `todos` ON `todos`.id = `comments`.todo_id SET `trashed` = 1 WHERE (`comments`.`trashed` = 0 AND `todos`.`todolist_id` = 968316918)
Hope this helps!