searching through joined polymorphic association with table_name defined - ruby

i have two models
class Profession < ApplicationRecord
has_many :users
end
class User < ApplicationRecord
self.table_name = 'accounts'
belongs_to :scope, polymorphic: true
end
and a query:
Profession.joins(:users).where(accounts: {scope: some_scope_variable })
when I run that i get
Mysql2::Error: Unknown column 'accounts.scope' in 'where clause'
what i also tried is
Profession.joins(:users).where(users: {scope: some_scope_variable })
but it also doesnt work and gives similar error
Mysql2::Error: Unknown column 'users.scope' in 'where clause'

According to the documentation, polymorphic associations rely on two columns being present on the model. Example
class User < ApplicationRecord
belongs_to :thingable, polymorphic: true
end
These columns should exist on users:
thingable_id
thingable_type
If you want to query them through an association, you may use the columns directly, like:
Profession.joins(:user).where(users: { thingable_id: 42, thingable_type: 'Foo' })
Also, I'd reconsider the name scope, since this is used by Rails already.
EDIT:
After submitting the answer above, I started understanding your question, sorry about this.
I reproduced it and made it work like this:
class Profession < ApplicationRecord
has_many :users, as: :thingable # <-- this is missing in your case
end
class User < ApplicationRecord
self.table_name = 'accounts'
belongs_to :profession
belongs_to :thingable, polymorphic: true
end
Now we can do this:
Profession.joins(:users).where(accounts: { age: (20..30) })
The WHERE-clause on the joined table is translated to SQL without any magic and checks:
WHERE `accounts`.`age` BETWEEN 20 AND 30
Whereas, the WHERE-clause on self-columns are sometimes magically modified:
User.where(thingable: 42)
results in
WHERE `accounts`.`thingable_id` = 42
-- ^^^ added by Rails
So, if we want to filter on any of these polymorphic columns, we do
Profession.joins(:users).where(accounts: { thingable_id: 111 })

Related

How to join 1:N tables in rails and instead of multiple rows for record get one row with extra column containing array of IDs from joined table

I have 3 models
class Mission < ActiveRecord::Base
belongs_to :guild
end
class Guild < ActiveRecord::Base
has_many :missions
has_many :guild_coordinators, :dependent => :destroy
has_many :coordinators, :through=> :guild_coordinators, :class_name => "Associate"
end
class GuildCoordinator < ActiveRecord::Base
belongs_to :guild
belongs_to :coordinator, :class_name => "Associate"
end
If I do
Mission.joins(:guild => :guild_coordinators)
I get row for every guild -> guild coordinator association
Is it possible to get unique records for Missions with joined Guilds and in one column get IDs of all coordinators in an Array?
edit:
expected result is something like this:
#<ActiveRecord::Relation [#<Mission id: 13, fy: 2018, guild_id: 31, name: "test mission", status: 0, coordinators: [1,2,3,5,8]>
my database is postgres
as output I need Active Record relation for gem ajax-datatables-rails
With Postgresql you can use array_agg aggregate function:
Mission.
joins(guild: :guild_coordinators).
select('missions.*, array_agg(guild_coordinators.id) as coordinators').
group(:id)
And you get exactly ActiveRecord::Relation, which will contain(after call) Mission objects with additional field coordinators:Array.
The second option is to use .includes like my or #garrett-motzner comments show.

has_and_belongs_to_many model creation needed?

I have orders and items table. I also have a third table called orders_items. Which I learned on creating from the following link (2nd graph) http://www.tutorialspoint.com/ruby-on-rails/rails-models.htm
models/order.rb
class Order < ActiveRecord::Base
has_and_belongs_to_many :items, through: :item_order
end
models/item.rb
class Item < ActiveRecord::Base
has_and_belongs_to_many :orders, through: :item_order
end
[orders_items] table has the following:
integer :order_id
integer :item_id
Do I have to create a models/order_item.rb file to add:
belongs_to :order
belongs_to :item
If so what is the correct naming format that it should be?
Would the name for the model file [order_item.rb] correct to distinguish which table it refers to?
models/order_item.rb ??
class OrdersItem ??? < ActiveRecord::Base
belongs_to :order
belongs_to :item
end
From the API
The join table should not have a primary key or a model associated
with it. You must manually generate the join table with a migration
such as this
class CreateDevelopersProjectsJoinTable < ActiveRecord::Migration
def change
create_table :developers_projects, id: false do |t|
t.integer :developer_id
t.integer :project_id
end
end
end
Specifies a many-to-many relationship with another class. This
associates two classes via an intermediate join table. Unless the join
table is explicitly specified as an option, it is guessed using the
lexical order of the class names. So a join between Developer and
Project will give the default join table name of “developers_projects”
because “D” precedes “P” alphabetically
In your case the join table name should be items_orders.
Your model must be named OrderItem. And you don't need belongs_to in this class. The file name (order_item.rb) is correct.
I think you need this relationship to fulfill your needs, except if orders is an item too
class Order < ActiveRecord::Base
has_many :items
end
and
class Item < ActiveRecord::Base
belongs_to :order
end

How can I do a LIKE query using an association?

Using ActiveRecord, how can I do a LIKE query based on a property of an association? Specifically, I'm looking for something that works with polymorphic associations.
class Invoice < ActiveRecord::Base
has_one :private_note, class_name: '::Note', as: :noteable,
conditions: {label: 'private'}
has_one :public_note, class_name: '::Note', as: :noteable,
conditions: {label: 'public'}
end
class Note < ActiveRecord::Base
belongs_to :noteable, polymorphic: true
validates :content, :presence: true
end
I want to find invoices whose private_note has a content column containing the word "friendly".
Use #merge
This can be accomplished with the .merge method.
Invoice.joins(:private_note).merge(Note.where("content LIKE ?", '%friendly%'))

Many-to-Many Uniqueness Constraint Test Not Working

I have a many-to-many relationship with a join table in my Rails application. I'm using the has_many :through idiom in my models. To keep things simple, lets call my first class Student, my second class Course, and the join table class Enrollment (which contains fields student_id and course_id). I want to make sure that a given Student is associated with a given Course at most once (i.e. the {student_id, course_id} tuple should be unique in the enrollment table).
So I have a migration a that enforces this uniqueness.
def change
add_index :enrollments, [:student_id, :course_id], :unique => true
end
In addition my model classes are defined as such:
class Student < ActiveRecord::Base
has_many :enrollments
has_many :courses, :through => :enrollment
end
class Course < ActiveRecord::Base
has_many :enrollments
has_many :students, :through => :enrollment
end
class Enrollment < ActiveRecord::Base
belongs_to :student
belongs_to :course
validates :student, :presence => true
validates :course, :presence => true
validates :student_id, :uniqueness => {:scope => :course_id}
end
In a rails console, I can do the following:
student = Student.first
course = Course.first
student.courses << course
#... succeeds
student.courses << course
#... appropriately fails and raises an ActiveRecord::RecordInvalid exception
In my RSpec test, I do the exact same thing and I get no exception with the following code:
#student.courses << #course
expect { #student.courses << #course }.to raise_error(ActiveRecord::RecordInvalid)
And so my test fails and reports:
expected ActiveRecord::RecordInvalid but nothing was raised
What's going on here? What could I be doing wrong? How do I fix it?
Rails uses model level validation, if you want strict checking for uniquiness you need to use database level - foreign keys for example. But in this case you need to catch exceptions from database connector.
This is strange because in my code (very similar to your) validation for unique raises exception.
There's a couple of things here that could be happening:
#courses has changed between uses.
#student has changed between uses.
By using let you'll protect these values from changing between expectations.
let(:course) { Course.first }
let(:student) { Student.first }
subject{ student.courses << course << course }
it { should raise_error(ActiveRecord::RecordInvalid) }
Or, there could just be something wrong with your code :)

Rails 3.1 distinct find and missing attributes

class State < ActiveRecord::Base
has_many :cities
end
class City < ActiveRecord::Base
belongs_to :state
has_many :companies
end
class Company < ActiveRecord::Base
belongs_to :city
end
I'm trying to list all states, and their respective cities, that contain at least one company registered. My first try was the following query:
states = State.joins(:cities => :companies).includes(:cities)
Which works, but I end up getting duplicates if a state has more than one city with companies in it. I then changed the query to:
states = State.joins(:cities => :companies).includes(:cities).select("distinct(states.id)")
This query almost works. I have access to the cities (states[0].cities), and there are no duplicates, but if I try to access an attribute from the State object, I get the following error:
ruby-1.9.2-p290 :056 >states[0].name
ActiveModel::MissingAttributeError: missing attribute: name
How can I solve this?
Thanks in advance
Your select statement overrides the default (SELECT * FROM ... becomes SELECT distinct(state.id) FROM...) so the results don't include the columns of your state table (where the attributes are inferred from). Try changing your select method to the following:
.select("distinct(states.id), states.*")

Resources