Using scopes in Rails 3 - ruby-on-rails

I am trying to define a scope in my Account model but it is not working. Here is my code:
class Account < ActiveRecord::Base
has_many :organizations
scope :primary, joins(:organizations).where('organizations.primary = ?', true)
accepts_nested_attributes_for :organizations
end
class Organization < ActiveRecord::Base
belongs_to :account
has_many :locations
accepts_nested_attributes_for :locations
end
From the console, I tried the following command:
Account.primary.first
But I get the following error:
ActiveRecord::StatementInvalid: SQLLite3::SQLException: near "primary":
syntax error: SELECT "accounts".* FROM "accounts" INNER JOIN "organizations" ON
"organizations"."account_id" = "accounts"."id" WHERE (organizations.primary = 't')
LIMIT 1
I think the name 'primary' might be causing the problem. When I renamed the scope to "important" and tried that I get:
NoMethodError: undefined method 'important' for #<Class:0x1f4a900>
If anyone can help I would very much appreciate it.

I think your problem is that you have a column named "primary" and that's a reserved word. Try quoting it:
scope :primary, joins(:organizations).where('organizations."primary" = ?', true)
This exception:
SQLLite3::SQLException: near "primary":
is coming from SQLite, not from ActiveRecord or Rails.

Related

Trouble with simple Rails nested associations where clause for parent

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

Rails scope query on model

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

merging multiple models in rails 3.2 so that users can log in under multiple subdomains using devise

I'm using devise for authentication and am stumped by the way that my users are associated with the subdomains they can log in under. I've studied the info plataformatec provides here and the great post by Dave Kenedy on Ruby Source here. I still don't quite understand joins and queries well enough to make this work, though.
class User < ActiveRecord::Base
has_many :residences
...
end
class Residence < ActiveRecord::Base
belongs_to :user
belongs_to :apartment
...
end
class Apartment < ActiveRecord::Base
has_many :residences
belongs_to :building
...
end
class Building < ActiveRecord::Base
attr_accessible :subdomain
has_many :apartments
...
end
In config/initializers/devise.rb I've added:
config.request_keys = [:subdomain]
In app/models/user.rb I've replaced the default devise method, `self.find_for_authentication with:
def self.find_for_authentication(conditions={})
conditions[:residences] = { :subdomain => conditions.delete(:subdomain) }
find(:first, :conditions => conditions, :joins => :residences)
end
When I run my specs I get the following error:
PG::Error: ERROR: column residences.subdomain does not exist
I know that somehow I've got to join my residence table all the way to the building table to confirm that the user signing in is affiliated with a building with the right subdomain but I don't know how to do it. Anyone have any ideas? The Rails Docs has info on joining tables but that confuses me too. (Basic info on databases and joining tables would help, too. ;-) )
Update
I've revised in app/models/user.rb
def self.find_for_authentication(conditions={})
subdomain = conditions.delete(:subdomain)
building = Building.find_by_subdomain(subdomain)
apartments = Apartment.where('apartment.building_id' => building.id)
conditions[:residences] = { :apartment_id => apartments }
find(:first, :conditions => conditions, :joins => :residences)
end
This might be a little closer to what I need but I'm still getting the following error in rspec:
1) UserSubdomainLogins signin should not be able to signin to building without access
Failure/Error: click_button "Sign in"
ActiveRecord::StatementInvalid:
PG::Error: ERROR: missing FROM-clause entry for table "apartment"
LINE 1: ...SELECT "apartments"."id" FROM "apartments" WHERE "apartment...
^
: SELECT "users".* FROM "users" INNER JOIN "residences" ON "residences"."user_id" = "users"."id" WHERE "users"."email" = 'daniela#lehner.biz' AND "residences"."apartment_id" IN (SELECT "apartments"."id" FROM "apartments" WHERE "apartment"."building_id" = 2895) ORDER BY last_name ASC LIMIT 1
In your revision you need to change apartment to apartments:
apartments = Apartment.where('apartments.building_id' => building.id)
Here's how to do it using joins:
#subdomain is already in the conditions so you don't need to do anything
def self.find_for_authentication(conditions={})
find(:first, :conditions => conditions,
:joins => {:residences => {:apartment => :building }})
end
See section 11.2.4 in the following guide for more information about the nested joins using hashes.
http://guides.rubyonrails.org/active_record_querying.html#joining-tables

No Such Column - When Column Exists

Not sure how this is happening but it's saying the column doesn't exist:
SQLite3::SQLException: no such column: element.kind: SELECT COUNT(*) FROM "answers" INNER JOIN "elements" ON "elements"."id" = "answers"."element_id" WHERE "answers"."form_id" = 55 AND "element"."kind" = 6
# element.rb
class Element < ActiveRecord::Base
has_many :answers
end
# answer.rb
class Answer < ActiveRecord::Base
belongs_to :element
belongs_to :form
end
class Form < ActiveRecord::Base
has_many :answers
end
But when I run:
#form.answers.joins(:element).where(:element => {:kind => 6})
I get the sql error above. Not sure what's going on. Any thoughts on what I'm missing?
Thanks!
FYI I'm running rails 3.2.3 with ruby 1.9.3.
The table is elements rather than element as generated by the query ("element"."kind" = 6).
#form.answers.joins(:elements).where(:elements => {:kind => 6})
I would have expected the rest of the query to be generated using the nonexistent element table as well, since you used .joins(:element) instead of .joins(:elements) but perhaps Rails is pluralizing inside .joins() for a belongs_to association.
#form.answers.joins(:element).where(:elements => {:kind => 6})

update_all through an association

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!

Resources