Scratching my head here... If I try the following with rails:
User.limit(25).includes([:addresses])
I get:
User Load (109.5ms) EXEC sp_executesql N'SELECT TOP (25) [User].* FROM [User]'
Address Load (112.3ms) EXEC sp_executesql N'SELECT [Address].* FROM [Address] WHERE [Address].[UserId] IN (N''1'', N''2'', N''3'', N''6'', N''7'', N''8'', N''9'', N''11'', N''12'', N''16'', N''17'', N''18'', N''19'', N''20'', N''21'', N''22'', N''24'', N''25'', N''26'', N''27'', N''28'', N''29'', N''30'', N''31'', N''34'')'
(Object doesn't support #inspect)
=>
If I instead do
#users = User.limit(25).joins([:addresses])
this works fine, however an inner join is not what I want not to mention I'm actually trying to do this through sunspot_rails which only supports includes.
I'm not entirely sure what is up with this error. I suspect it might be due to the fact that this is a legacy MSSQL database so the naming conventions are nowhere near what rails likes. However I'm at a loss as to what the specific issue is.
The models are as follows, stripped down to the minimum which is verified to reproduce the problem:
class User < ActiveRecord::Base
set_table_name "User"
set_primary_key "ID"
has_many :addresses, :foreign_key => 'UserId'
end
class Address < ActiveRecord::Base
set_table_name "Address"
set_primary_key "ID"
belongs_to :user
end
That is it. There is other code on the user model for searching and authentication, but I've commented that all out and verified it has no impact on this problem. I'm stuck on this, any help is appreciated. The app is using rails 3.1, with activerecord-sqlserver-adapter and tiny_tds.
Solved...
:foreign_key => "UserID", not :foreign_key => "UserId"
For some reason, the case difference does not seem to bother rails when doing non eager loading, or with .joins, but does with .includes. Doh.
Related
First post I've ever felt I had to make here, normally my questions are answered by just reading other posts but this time I think I'm in too deep to find the proper answer, I've been looking for quite a while. I may have multiple issues going on in my code.
I'm a novice with RoR, just started working with it the last couple of months. I'm attempting to run a test query to make sure my associations are working properly, and based on the errors I'm getting, I feel like I've messed up something simple. I'm setting up a couple of tables for a webapp, I'll focus on 2 tables for now because a fix to this can be applied elsewhere afterwards.
Pertinent information:
-I'm using Devise for user authentication
-I have a pto_requests_controller.rb and registrations_controller.rb (registrations is used with devise as a user controller)
-In the database, the table names are 'users' and 'pto_requests'
I have a pto_request model (filename is 'pto_request.rb'):
class PtoRequest < ApplicationRecord
belongs_to :user, optional: true
end
And a user model (filename is 'user.rb'):
class User < ApplicationRecord
has_many :pto_requests
end
To create associations in the database, I used this migration:
class AddUsersToPtorequests < ActiveRecord::Migration[5.1]
def change
add_reference :pto_requests, :users, foreign_key: true
end
end
The foreign key was created in the 'pto_requests' table and called 'users_id'
I can query the tables individually with no issues, but once I try to access data like, for example, user.fname through pto_requests, it errors out. As an example query I've tried:
<%= PtoRequest.joins(:user)
.select('user.fname as user_name').first.user_name%>
I receive the following error:
Mysql2::Error: Unknown column 'user.fname' in 'field list': SELECT user.fname >as user_name FROM pto_requests INNER JOIN users ON users.id = >pto_requests.user_id ORDER BY pto_requests.id ASC LIMIT 1
My current theory is it has something to do with an issue in the end of the generated SQL syntax as it is looking for 'user_id' but this does not exist, only 'users_id' does. Any help is greatly appreciated, and if any more information is required please let me know.
You have missunderstood the associations completely.
belongs_to creates a one-to-one or one-to-many association and places the foreign key column on this models table:
class PtoRequest < ApplicationRecord
belongs_to :user, optional: true
end
This association thus will reference pto_requests.user_id. You have added the foreign key to the wrong table.
To generate the correct migration run:
rails g migration add_user_to_pto_requests user:references
The enitity you are referencing should always be singular.
I have a basic database with a structure like this.
products
------------------
id
serial
order
------------------
id
product_serial
Unfortunately, I cannot change structure of the DB. I looked at the docs for Rails 2.1 and it said I could setup a relationship like this.
belongs_to :product,
:class_name => 'Product',
:foreign_key => 'product_serial',
:primary_key => 'serial'
However, that gives me this error.
Unknown key: primary_key
Without the primary key it produces this SQL
SELECT * FROM `products` WHERE (`products`.`id` = #{serial})
How do I setup a belongs_to relationship on this?
EDIT For the record, I am working in Rails 2.1. (I know, don't tell me).
If you check the available options for the belongs_to association for the Rails 2 branch, you'll see that :primary_key is not one of them.
It should be enough, in your case, to simply state the foreign key as you did in the previous line.
Your order model does not have a field (and thus method) which is called serial. You don't need to specify it, then it defaults to id (which you do have).
I'm using Rails 2.3.14
UPDATE 3 the trick I found in update 2 only works for the first access of the association... so, I stick the set_table_name lines in my application controller. This is so weird. I hope this gets fixed. =\
UPDATE 2 if I manually / nastily / hackily set teh tables for the troublesome classes at the bottom of my environment file, I stop getting the errors.
app/config/environment.rb:
Page::Template::Content.set_table_name "template_page_contents"
Page::Template::Section.set_table_name "template_page_sections"
Why do I have to do this? is rails broken for this particular use case?
UPDATE: it appears that set_table_name isn't working when it's initially called in my Page::Template::Content class.
but if I call it right before I use the association, it works...
ap Page::Template::Content.table_name # prints "contents"
Page::Template::Content.set_table_name "template_page_contents"
ap Page::Template::Content.table_name # prints "template_page_contents"
return self.page_template_contents.first # doesn't error after the above is exec'd
ORIGINAL QUESTION:
TL; DR: I have a has_many relationship that I'm trying to access, but Rails thinks that the table that the has_many relationship uses is a different table
I've been getting this error, where when I try to access a Page::Template::Content that belongs_to a Page::Template via a has_many relationship.
Mysql2::Error: Unknown column 'contents.template_page_id' in 'where clause': SELECT * FROM `contents` WHERE (`contents`.template_page_id = 17) LIMIT 1
Looking at the error logs, I figured I needed to starting using some print statements to find out why rails was trying to find the associated objects in the wrong table.
gems_path/activerecord-2.3.14/lib/active_record/associations/association_collection.rb:63:in `find'
I just decided to print the #reflection object since everything seems to be happening around that. Here is how I did that:
require "awesome_print" # best console printer (colors, pretty print, etc)
def find(*args) # preexisting method header
ap "-------" # separator so I know when one reflection begins / ends, etc
ap #reflection # object in question
... # rest of the method
Last '#reflection' that printed before the error:
"-------"
#<ActiveRecord::Reflection::AssociationReflection:0x108d028a8
#collection = true,
attr_reader :active_record = class Page::Template < LibraryItem {...},
attr_reader :class_name = "Page::Template::Content",
attr_reader :klass = class Content < LibraryItem {...},
attr_reader :macro = :has_many,
attr_reader :name = :page_template_contents,
attr_reader :options = {
:foreign_key => "template_page_id",
:class_name => "Page::Template::Content",
:extend => []
},
attr_reader :primary_key_name = "template_page_id",
attr_reader :quoted_table_name = "`contents`"
>
there are a couple things wrong in the above block of code.
:klass should be Page::Template::Content
:name should be :contents
:quoted_table_name should be `contents`
How my models are set up:
app/models/page.rb:
class Page < LibrayItem
belongs_to :template_page, :class_name => "Page::Template"
app/models/page/template.rb
class Page::Template < Library Item
set_table_name "template_pages"
has_many :page_template_contents,
:class_name => "Page::Template::Content",
:foreign_key => "template_page_id"
app/models/page/template/content.rb
class Page::Template::Content
set_table_name "template_page_contents"
belongs_to :template_page,
:class_name => "Page::Template",
:foreign_key => "template_page_id"
class Page::Template
...
return self.page_template_contents.first
the class the association is choosing (unrelated to my page / template structure above):
class Content < LibraryItem
set_table_name "contents"
# no associations to above classes
So... what is causing this and how do I fix it?
Your issue is not due to set_table_name but rather due to how Rails finds the target model class in an association and the fact that you have a top-level model (Content) which shares its name with a model nested in a deeper namespace (Page::Template::Content). The weird difference in behaviour is most likely due to differences in what classes are actually loaded at the time the association is examined (remember that by default in development mode Rails loads model classes on demand when they are first referenced).
When you define an association (whether you specify the class name of the target model of the association explicitly as you have done or accept the default), Rails has to turn the name of the target model class into a Ruby constant so that it can refer to that target class. To do this, it invokes the protected class method compute_type on the model class that is defining the association.
For example, you have
class Page::Template < LibraryItem
set_table_name "template_pages"
has_many :page_template_contents,
:class_name => "Page::Template::Content",
:foreign_key => "template_page_id"
end
You can test in the Rails console how compute_type works for this class:
$ ./script/console
Loading development environment (Rails 2.3.14)
> Page::Template.send(:compute_type, "Page::Template::Content")
=> Page::Template::Content(id: integer, template_page_id: integer)
I see the result is, as I expect, a reference to the class Page::Template::Content.
However, if I restart the Rails console but this time cause the model class Content to be loaded first (by referencing it) and then try again, I see this (I didn't bother creating a table for the Content model, but that doesn't change the significant behavior):
$ ./script/console
Loading development environment (Rails 2.3.14)
>> Content # Reference Content class so that it gets loaded
=> Content(Table doesn't exist)
>> Page::Template.send(:compute_type, "Page::Template::Content")
=> Content(Table doesn't exist)
As you can see, this time I get a reference to Content instead.
So what can you do about this?
Well, first of all, you should realize that using namespaced model classes in Rails (certainly in 2.3) is a real pain. It's nice to organize your model classes in a hierarchy but it certainly does make life more difficult. As you can see above, if you have a class in one namespace that has the same name as a class in another namespace, this gets more hairy.
If you still want to live with this situation, I can make a couple of suggestions. One of the following may help:
Turn on class caching in development mode. This will cause all model classes to be preloaded rather than loading them on demand as is the default. It will make your code above more predictable, but may make development somewhat unpleasant (since classes will no longer be reloaded with each request).
Explicity require dependent classes in classes with problematic associations. For example:
class Page::Template < LibraryItem
require 'page/template/content'
set_table_name "template_pages"
has_many :page_template_contents, ...
end
Override the compute_type method in your classes where you know referencing associated class may go awry so that it returns the namespaced class no matter what. Without knowing your class hierachy in more detail I cannot give a full suggestion on how to do this, but a quick and dirty example follows:
class Page::Template < LibraryItem
set_table_name "template_pages"
has_many :page_template_contents,
:class_name => "Page::Template::Content",
:foreign_key => "template_page_id"
def self.compute_type(type_name)
return Page::Template::Content if type_name == "Page::Template::Content"
super
end
end
We recently upgraded our rails app from version 3.0.3 to 3.1.0. The application runs successfully for the most part as it did before with one major exception. We have a many-to-many relationship between two models, SurveyDatum and SubGroup, joined via a model called SubGroupSurveyDatum. Here is the code for each:
class SurveyDatum < ActiveRecord::Base
has_many :sub_group_survey_data
has_many :sub_groups, :through => :sub_group_survey_data
end
class SubGroup < ActiveRecord::Base
has_many :sub_group_survey_data
has_many :survey_data, :through => :sub_group_survey_data
end
And as you might expect:
class SubGroupSurveyDatum < ActiveRecord::Base
belongs_to :survey_datum
belongs_to :sub_group
end
If I have a SurveyDatum object that I retrieved previously from the database (lets call it 'sd'), and I invoke the sub_groups method (sd.sub_groups), this is the resulting sql query generated by active record:
SELECT `sub_groups`.* FROM `sub_groups` INNER JOIN `sub_group_survey_data` ON `sub_groups`.`id` = `sub_group_survey_data`.`sub_group_id` WHERE `sub_group_survey_data`.`survey_datum_id` IS NULL
The "IS NULL" part is obviously where the id of my survey data object is supposed to go, however active record fails to use it. The object does indeed have an id, since as mentioned it was persisted and retrieved from the database. This problem only cropped up after we moved to rails 3.1, so I assume there's something I've not done properly in accordance with the new version, but I have no idea. Any ideas? Thank you in advance for your help!
Hmm I used rails 3.1.0 and tried to replicate but all was well. The only case was when I manually set id = nil on the record retrieved from the db. Then I got:
SELECT "authors".* FROM "authors" INNER JOIN "relations" ON "authors"."id" = "relations"."author_id" WHERE "relations"."post_id" IS NULL
What database are you using? I was trying this with sqlite3. Also watch out for certain gems especially those that work with ActiveRecord. I had trouble with this in the past.
We discovered the issue. I had forgotten that the survey_data table has a composite primary key. When we upped to version 3.2.3, and added in the SurveyDatum model the following:
set_primary_key :id
The query finally built and executed properly.
I am making a site in RoR and I am inside a multi DB environment. By that, I mean that some of my models are linked to MSSQL tables, and some others are linked to MYSQL tables.
It works well for the most part, but when I use the 'include' option in a find method, I get a very weird mix of SQL. Let me show you an example:
[SELECT * FROM "viewInfoClient" WHERE ("viewInfoClient".`NoClient` IN (6044196,5000652,0204392)) ]
MSSQL uses " between tables and columns name
MYSQL uses `
When I use the :include option in a MYSQL model, it will try and go read the corresponding results in the MSSQL model table. Since the NoClient link field comes from my MYSQL model, it gets mixed and MSSQL throws an error which is logical.
[unixODBC][FreeTDS][SQL Server]Incorrect syntax near '`'
Any idea how I can solve this problem?
CLIENT MODEL (MSSQL Database)
class Client < ActiveRecord::Base
establish_connection "mssql_#{RAILS_ENV}"
set_table_name "viewInfoClient"
set_primary_key "NoClient"
has_many :billets, :foreign_key => 'noclient', :primary_key => 'NoClient'
end
BILLET MODEL (MySQL Database)
class Billet < ActiveRecord::Base
belongs_to :client, :foreign_key => 'noclient'
end
AFFECTED STATEMENT
Could be anything using :include in it between the 2.
Example from the Billet model
def findall
find(:all, :include => 'client', :conditions => 'bin_id = 1')
end
Will return:
SELECT * FROM "viewInfoClient" WHERE ("viewInfoClient".`NoClient` IN (6044196,5000652,0204392))
Where (6044196,5000652,0204392) are the 3 records that have bin_id = 1 in the Billet model.
I remove everything else from my models to shorten the code, but this is it basically. I can reproduce it from any model that uses a MySQL - MSSQL link.