#ruby-on-rails
#ruby-on-rails
Вопрос:
Я использую Rails 3.
У меня есть 3 модели:
class Deal < ActiveRecord::Base
has_many :wishes, :class_name => "Wish"
has_many :wishers, :through => :wishes, :source => :user
end
class User < ActiveRecord::Base
has_many :wishes, :class_name => "Wish", :conditions => { 'wishes.wished' => true }
has_many :wished_deals, :through => :wishes, :source => :deal
end
class Wish < ActiveRecord::Base
belongs_to :user
belongs_to :deal
end
И я пытаюсь создать следующую область в модели сделки:
scope :not_wished_by_user, lambda { |user| includes(:wishes).where('wishes.wished' != true, 'wishes.user_id' => user) }
Что я хочу, так это все сделки, за исключением тех, которые помечены как «желаемые» данным пользователем в блоке. Но всякий раз, когда я делаю это includes, я получаю следующую ошибку:
ruby-1.9.2-head > u = User.all.first
ruby-1.9.2-head > Deal.not_wished_by_user(u)
(Object doesn't support #inspect)
=>
Кроме того, помещение его в функцию не работает. Есть идеи, что это может быть?
Спасибо!
РЕДАКТИРОВАТЬ: Это перенос таблицы пожеланий
class CreateWish < ActiveRecord::Migration
def self.up
create_table :wishes do |t|
t.integer :deal_id
t.integer :user_id
t.boolean :wished, :default => true
t.boolean :collected, :default => false
t.datetime :collected_date
t.timestamps
end
add_index :wishes, [:deal_id, :user_id], :uniq => true
end
end
Комментарии:
1. Не уверен, решает ли это вашу проблему, но этот синтаксис неверен:
.where('wishes.wished' != true
. Так и должно быть.where('wishes.wished' => false
.2. Описание полей в таблице базы данных Желает
3. В любом случае, спасибо @mischa, это не решило проблему : (
Ответ №1:
Смотрите обновление ниже vv
Старый ответ
Вы не используете никаких Deal
атрибутов для selects, поэтому попробуйте переместить код в Wish
класс:
class Wish < ActiveRecord::Base
belongs_to :user
belongs_to :deal
scope :'wished?', lambda{ |f| where('wished = ?', f) }
scope :not_wished_by_user, lambda{|user| wished?(false).where('user_id = ?', user)}
end
Пример использования и вывод:
ruby-1.9.2-p180 :023 > Wish.not_wished_by_user(User.first).to_sql
=> "SELECT "wishes".* FROM "wishes" WHERE (wished = 't') AND (user_id = 1)"
Для вас это правильный результат?
PS:
В Deal
вы можете оставить прокси-метод, подобный:
class Deal < ActiveRecord::Base
has_many :wishes, :class_name => "Wish"
has_many :wishers, :through => :wishes, :source => :user
def self.not_wished_by_user(user)
Wish.not_wished_by_user(user)
end
end
Update1 (подзапрос)
class Deal < ActiveRecord::Base
has_many :wishes, :class_name => "Wish"
has_many :wishers, :through => :wishes, :source => :user
scope :deal_ids_not_wished_by_user, lambda { |user|
joins(:wishes).where('wishes.user_id = ?', user).where('wishes.wished = ?', false).select('deals.id')
}
scope :wished_by_user, lambda { |user|
where("id not in (#{Deal.deal_ids_not_wished_by_user(user).to_sql})")
}
end
Пример использования и вывод:
ruby-1.9.2-p180 :023 > Deal.wished_by_user(User.first).to_sql
=> "SELECT "deals".* FROM "deals" WHERE (id not in (SELECT deals.id FROM "deals" INNER JOIN "wishes" ON "wishes"."deal_id" = "deals"."id" WHERE (wishes.user_id = 1) AND (wishes.wished = 'f')))"
UPD2 (внешнее соединение в стиле rails)
Класс Deal:
class Deal < ActiveRecord::Base
has_many :wishes, :class_name => "Wish"
has_many :wishers, :through => :wishes, :source => :user
scope :not_wished_excluded, lambda { |user|
joins('LEFT OUTER JOIN wishes on wishes.deal_id = deals.id').
where('wishes.user_id = ? OR wishes.user_id is null', user).
where('wishes.wished = ? OR wishes.wished is null', true)
}
end
Использование:
ruby-1.9.2-p180 :096 > Deal.not_wished_excluded(User.first).to_sql
=> "SELECT "deals".* FROM "deals" LEFT OUTER JOIN wishes on wishes.deal_id = deals.id WHERE (wishes.user_id = 1 OR wishes.user_id is null) AND (wishes.wished = 't' OR wishes.wished is null)"
Комментарии:
1. Спасибо за ваш ответ. Это не то, чего я хочу. Проблема в том, что это даст мне только объекты Wishes, которые пользователю не нужны, но я хочу исключить объекты Deal, которые пользователь не хочет, но с которыми еще не обязательно связан объект Wish. Вот почему я делаю внешнее левое соединение, внутреннее соединение этого не сделает, потому что оно исключит все сделки, с которыми еще не связан объект Wish.
2. Обновленный ответ с вариантом подзапроса. Это то, что вам нужно?