Thinking Sphinx and multiple has_one - ruby-on-rails

I've got multiple has_one associations in my model
class Invoice < ActiveRecord::Base
...
belongs_to :seller, :class_name => "Client", :foreign_key => "provider", :conditions => ['is_provider = ?', true]
belongs_to :customer, :class_name => "Client", :foreign_key => "receiver", :conditions => ['is_receiver = ?', true]
I'm trying to index it:
indexes [seller(:tbClientCode), seller(:tbClientLabel), seller(:tbClientName), seller(:tbClientNIP),
seller(:tbClientRegon), seller(:tbClientZip), seller(:tbClientCity), seller(:tbClientStreet),
seller(:tbClientHouseNr), seller(:tbClientHomeNr], :sortable => true, :as => :seller_fields
has [seller(:is_provider), seller(:is_receiver)], :sortable => true, :as => :seller_attributes
indexes [customer(:tbClientCode), customer(:tbClientLabel), customer(:tbClientName), customer(:tbClientNIP),
customer(:tbClientRegon), customer(:tbClientZip), customer(:tbClientCity), customer(:tbClientStreet),
customer(:tbClientHouseNr), customer(:tbClientHomeNr], :sortable => true), :as => :customer_fields
has [customer(:is_provider), customer(:is_receiver)], :sortable => true, :as => :customer_attributes
... and then some error occurs
ERROR: index 'invoice_core': sql_range_query: ERROR: column reference "is_receiver" is ambiguous
LINE 1: ...tomers_invoices"."id" = "invoices"."receiver" AND is_receive...
Changing syntax from customer(:tbClientName) to customer.tbClientName is not solution.
Some help would be greatly appreciated

Well, firstly: I don't think you actually want to combine all those columns into just one field and just one attribute?
So, remove the [] - you can pass in multiple columns, but if you pass in an explicit array, then that'll group those columns together into a single field/attribute. Thus, remove the :as option as well - you don't want all of those columns together having the same name, the generated SQL statement won't make any sense.
Secondly: attributes are sortable by their very nature, so you don't need to pass :sortable => true to the has call. Also: do you really need all of the fields to be sortable? Better to only mark the fields that should be sortable as such.
But lastly, and perhaps most importantly: the error that's actually happening is because of your conditions hash for your two associations. You're joining on the same table twice, but you don't have any table references in the conditions. Try changing both conditions settings to the following:
:conditions => {:is_provider => true}
:conditions => {:is_receiver => true}

Related

Rails 4.0.0 foreign key for models

Is this wrong to have that same foreign key for two different models? It's Rails 4.0.0 app so conditions are written like that. I ask because I got some problem with blinks and can't find it.
has_many :messages, :conditions => {:deleted => false, :subject_h => ''}
has_many :messages_send, :class_name => "Message", :foreign_key => "sender_id", :conditions => ['deleted_sender = ?', false]
has_many :blinks, :conditions => {:deleted => false, :subject_h => ''}
has_many :blinks_send, :class_name => "Blink", :foreign_key => "sender_id", :conditions => ['deleted_sender = ?', false]
I would do one of the two following things:
1 - Have one table per model (so one blinks table and one messages table).
2 - Use Single Table Inheritance (STI) for each messages. You would have only one table (senders in your case), with a type field that would differentiate between a blink and a message.
For simplicity here, I would personally go for the first option, and evolve to the STI later on if still needed.
The advantage would also be that you'll be able to declare your associations like this:
has_many :messages
has_many :blinks

Using :include with nested tables through foreign_key relationships

A CertProgramItem has_many :cert_schedules.
A CertSchedule belongs_to :reg_fee_item, :foreign_key => 'reg_fee_item_id', :class_name => 'Item'
Starting with the CertProgramItem, I want to get all CertSchedules and their related tables in one query (to avoid the n+1 problem). My first query was:
cpi_arr = CertProgramItem.find(:all, :include => :cert_schedules, :order => :id)
However, this didn't fetch the members of the Item class which belong to the collection of CertSchedules.
I have modified the query:
cpi_arr = CertProgramItem.find(:all, :include => {:cert_schedules => :items}, :order => :id)
and
cpi_arr = CertProgramItem.find(:all, :include => {:cert_schedules => :reg_fee_items}, :order => :id)
but I get errors like ActiveRecord::ConfigurationError: Association named 'items' was not found; perhaps you misspelled it?" or ActiveRecord::ConfigurationError: Association named 'reg_fee_items' was not found; perhaps you misspelled it? for the 2nd.
Is there a way to get this nested, foreign-key association in one query?
Here's some more detailed information on the CertSchedule assocciations:
class CertSchedule < ActiveRecord::Base
belongs_to :cert_program_item
belongs_to :reg_fee_item, :foreign_key => 'reg_fee_item_id', :class_name => 'Item'
belongs_to :start_term, :class_name => 'SchoolTerm', :foreign_key => 'start_term_id'
My latest version of the query looks like this:
cpi_arr = CertProgramItem.find(:all, :include => [:cert_tier, {:cert_schedules => [:reg_fee_item,:start_term] }])
This query is now successfully returning what I expected. Lessons learned:
Use the foreign key name from the model, not the actual table name.
Multiple items in an association need to be surrounded with square brackets [].

Rails + Thinking-Sphinx polymorphic association

class User < ActiveRecord::Base
has_many :followings, :as => :followable, :dependent => :destroy, :class_name => 'Follow'
has_many :follows, :as => :follower, :dependent => :destroy
define_index do
has follows.followable(:id), :as => :followable_id
has followings.follower(:id), :as => :follower_id
has follows.followable(:type), :as => :followable_type
has followings.follower(:type), :as => :follower_type
end
end
question: I can not search by type (always empty array). A bug? I would like to get all users where followers are of type 'AAA'.
User.search '', :with => { :follower_type => 'AAA' }
question: Why do I have to inverse my association to get the right result (index definition):
follows.followable(:id), :as => :followable_id
instead of
followings.followable(:id), :as => :followable_id
I would like to get a list of followers for a user with id=1
User.search :with => {:followable_id => 1} # List of followers for a user with id=1
Thx!
With regards to the first question - string filters don't work in Sphinx. This should change in the future (with Sphinx 1.10-beta, once Thinking Sphinx supports the new features), but not sure when that'll happen (I'd love to say soon, but can't promise anything).
There is a workaround available, though... but keep in mind you're handling an array of strings, so that's an additional level of complexity.
As for the second question, struggling to get my head around what the database is looking like (confusing names, but I'm lacking focus right now), so I'll just leave it at this for the moment.

Why can't records with piggy-back attributes be saved?

I recently run into a problem where records were marked as readonly. Checking out the documentation I found this:
"Records loaded through joins with piggy-back attributes will be marked as read only since they cannot be saved. "
Why not? My model looks like the following:
class MailAccount
belongs_to :account, :class_name => "UserAccount"
named_scope :active, :joins => :account,
:conditions => "user_accounts.archived_at IS NULL"
end
I find no reason why models loaded retrieved with this named scope can not be saved. Any ideas?
It turned out I had to add :select => "mail_accounts.*" to the scope, or otherwise the query would store attributes from user_accounts in the MailAccount object, which prevented it from being saved.
So the proper code to use is:
class MailAccount
belongs_to :account, :class_name => "UserAccount"
named_scope :active, :joins => :account,
:conditions => "user_accounts.archived_at IS NULL",
:select => "mail_accounts.*"
end
When you use a :join, the ActiveRecord model for that associated object is not instantiated. You should use :include instead.

Rails - using :include to find objects based on their child's attributes

I have a sentence and correction model
class Sentence < ActiveRecord::Base
has_one :correction
class Correction < ActiveRecord::Base
belongs_to :sentence
and I'm trying find all sentences which don't have a correction. To do this I'm simply looking for corrections which don't exist i.e. whose id = nil. But it is failing and i can't figure out why
Sentence.find :all, :include => :correction, :conditions => {:correction => {:id => nil}}
from (irb):4>> Sentence.find :all, :include => :correction, :conditions => {:correction => {:id => nil}}
ActiveRecord::StatementInvalid: Mysql::Error: Unknown column 'correction.sentence_id' in 'where clause': SELECT * FROM sentences WHERE (correction.sentence_id IS NULL)
Perhaps its the syntax or maybe just the overall approach. Can anyone help?
You can use this:
Sentence.all(:include => :correction,
:conditions => "corrections.sentence_id IS NULL")

Resources