Ошибка Rails 3: Объект не поддерживает #inspect при включении (левое внешнее соединение)

#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. Обновленный ответ с вариантом подзапроса. Это то, что вам нужно?